Galapagos Tech Blog

株式会社ガラパゴスのメンバーによる技術ブログです。

PhoenixでSwaggerする

御機嫌よう。ガラパゴスのおとめです。

今日は、「次に来る大物Web言語」と前評判の高いElixirと、そのRailsぽいフレームワークPhoenixに触りつつ、RESTful APIを作るには欠かせないSwaggerドキュメントを生成してみようと思います。

あなたは、誰あれ?

はじめに登場人物の簡単な紹介をしておきましょう。

ElixirとPhoenix

ガラパゴススマートフォンアプリの開発を主な事業としている会社です。一口にスマートフォンアプリと言っても、そこは端末だけで完結する世界ではなく、サーバとのやりとりが必要になります。

もちろんサーバーサイドはどんな言語で実装しても構わないのですが、パフォーマンスが気になったり、ホットデプロイしたかったり、煩わしい設定ファイルを書きたくなかったり、JEEが嫌いだったり、ActiveRecordが遅かったり、しますよね?

そんな時、あなたの傍には、ElixirPhoenixが佇んでいます。

簡単に言うと、関数型ぽい言語にRailsぽいフレームワーク、速くてホットデプロイ上等でめっちゃRails、それがElixir + Phoenixです。Elixirが言語でPhoenixフレームワーク。と言われても「?」ですね。百聞は一見にしかず、とも申しますゆえ、実際に導入してみましょう。

Swagger?

ガラパゴススマートフォンアプリの開発を主な事業としている会社です。一口にスマートフォンアプリと言っても、そこは端末だけで完結する世界ではなく、サーバとのやりとりが必要になります。

でもでも、もしもあなたがサーバーサイドのエンジニアなら、どうやってAPIの仕様を公開するの? どうしたらちゃんとドキュメントのメンテナンスできるの? みたいなことを思いますよね? それに、もしもあなたがアプリのエンジニアなら、サーバにはどんなAPIがあるの? どんな仕様なの? ちょっと試してみたいんだけど? と思いますよね?

そう思った時、あなたの傍にはSwaggerが佇んでいます。

簡単に言うと、RESTful APIの仕様を記述するための仕様、それがSwaggerです。と言われても「?」ですね。百聞は一見にしかず、とも申しますゆえ、実際に導入してみましょう。

環境作成

まだElixirの環境をお持ちでない方も、公式の手順で簡単に用意することができます。Elixirの環境ができたらおもむろにPhonenixもインストールしましょう。

また、Phoenixでは、デフォルトのデータベースがPostgreSQLになっていますので、必要ならインストールします。もしも事情があってPostgreSQLをインストールできない場合、この先の手順が多少変わったり、設定ファイルを変更したりする必要があります。この記事では、PostgreSQLを使えるものとして書いていきます。

なお、PostgreSQLはインストール直後のデフォルト設定ではpostgresユーザーでしか接続できませんので、pg_hba.confを適切に変更しておきます。

次にSwagger UIをインストールします。これは、生成したSwaggerドキュメントを表示するために使います。

Swagger UIにはWebサーバが必要ですのでお好みで。ここではnginxを使います。nginxをインストールしたら必要なファイルをコピーします。

$ git clone https://github.com/swagger-api/swagger-ui
$ sudo cp -R swagger-ui/dist /var/www/html/

アクセスしたら次のような画面が出てきましたね?

f:id:glpgsinc:20160825194932p:plain

プロジェクトの作成

必要な環境ができたら、いよいよプロジェクトを作ります。もちろん皆様はこの記事をここまで読む間に公式のガイドをチラ見くらいはしていて、すでにRailsをお使いの方なら、めっちゃRailsだとお分かりだと思います。rails newくらいに気軽に行ってみましょう(ここではswagger_sample_appとしていますが、もちろんお好みの名前をつけることができます)。

$ mix phoenix.new swagger_sample_app

実行すると、Railsをお使いの方にはどこかしら見覚えのある世界が出現すると思います。こんな風に。御機嫌よう世界。

swagger_sample_app
 +- config
 +- web
 |   +- controllers
 |   +- models
 |   +- views
 |   +- router.ex
 +- test
 +- mix.exs
 +- mix.lock

この他にもいろいろなファイルやらディレクトリやらができますが、とりあえずここでは、次のような対応が分かればよいでしょう。

Rails Phoenix
Gemfile mix.exs
Gemfile.lock mix.lock
config/routes.rb web/router.ex
appディレクト webディレクト

なお、Railsdatabase.ymlなどに相当するものはなく、Phoenixでは、config/dev.exsなどの、config配下の各ステージのファイルに記述していくことになります。

APIの作成

Phoenixでは、scaffoldどーん♪ みたいな感じで、APIも作れます。

$ mix phoenix.gen.json Sample samples foo:integer bar:string

実行したらルーティングとマイグレーションに関するメッセージが表示されたと思います。

まずルーティングの設定をします。メッセージはweb/router.exに書いて、みたいなあっさりしたものだったと思いますが、scopeや、今回作成するのはAPIですので、pipe_through :apiなども書く必要があります。

scope "/", SwaggerSampleApp do
  pipe_through :api
  resources "/samples", SampleController, except: [:new, :edit]
end

次にマイグレーションしましょう。まだデータベースを作っていないので、まずはデータベースの作成から。といってもrake db:create && rake db:migrateと同じくらいの感じでいけます。

$ mix ecto.create
$ mix ecto.migrate

これでCRUDを備えたAPI一式ができてしまいます。さらにはRailsにGrapeを導入した時のようにroutes.rakeをちょっと書くなどというひと手間もなく、作ったAPIのルーティングを確認することができます。

$ mix phoenix.routes
  page_path  GET     /             SwaggerSampleApp.PageController :index
sample_path  GET     /samples      SwaggerSampleApp.SampleController :index
sample_path  GET     /samples/:id  SwaggerSampleApp.SampleController :show
sample_path  POST    /samples      SwaggerSampleApp.SampleController :create
sample_path  PATCH   /samples/:id  SwaggerSampleApp.SampleController :update
             PUT     /samples/:id  SwaggerSampleApp.SampleController :update
sample_path  DELETE  /samples/:id  SwaggerSampleApp.SampleController :delete

デフォルトのインデックスページのほかに、sample_pathに今回作ったAPIができていますね。早速試してみましょう。

まず、phoenixを起動します。デフォルトでは4000番ポートで起動します。

$ mix phoenix.server

APIをコールしてみます。

$ curl http://127.0.0.1:4000/samples
{"data":[]}

まだ何も登録していないので空配列が帰ってきました。

Swaggerドキュメントの作成

さて、APIができたのでドキュメントを公開しましょう。

まず、プロジェクトにSwaggerを導入します。今回はphoenix_swaggerを使ってみます。

  # ...
  defp deps do
    [# ...,
     {:phoenix_swagger, path: "~> 0.1.4"}]
  end
  # ...
  def swagger_info do
    [version: "0.0.0", title: "Swagger sample"]
  end
  # ...

依存関係をインストールします。

$ mix deps.get

では、先ほど作成したAPIにドキュメントを書いていきましょう。ここではさわりとして、GET /sampesのドキュメントを書いてみます。

swagger_modelAPIの説明を書きます。また、レスポンスの型を明示したい時には、responsesの3番目のパラメタを指定します。このパラメタはfunction/0ですので、Swaggerに対応したレスポンスを返す関数を書きます。今回の例ではindex_schemaになります。

defmodule SwaggerSampleApp.SampleController do
  use SwaggerSampleApp.Web, :controller
  use PhoenixSwagger

  alias SwaggerSampleApp.Sample

  plug :scrub_params, "sample" when action in [:create, :update]

  swagger_model :index do
    description "登録したレコードの一覧を取得します"
    responses 200, "一覧", index_schema
  end

  def index_schema do
    %{type: :array, title: "一覧データ",
      items:
        %{title: "レコード",
          type: :object,
          properties: %{foo: %{type: :integer},
                        bar: %{type: :string}}}
     }
  end

  def index(conn, _params) do
  # ...

では、Swaggerで読み込むためのjsonを生成しましょう(プロジェクトのルートディレクトリで実行します)。

$ mix phoenix.swagger.generate

実行すると、swagger.jsonが出力されましたね? nginxで表示するために、/var/www/htmlあたりにコピーしまして、先ほどブラウザで表示したSwaggerで、おもむろにswagger.jsonのURLを入力してExploreしてみましょう。

するとこのように、先ほど書いたドキュメントが出てきましたね?

f:id:glpgsinc:20160825195006p:plain

でも、諸兄諸姉は、RDocやJavadoc、もしかしたら万が一、Excel仕様書などと比べて何がいいのか、などとお思いでありましょう?

CORSの設定

先に進む前に、CORSの設定を行います。SwaggerとPhoexnixは別のサイトになりますので、アクセスを許可する必要があります。

Phoenixの設定

今回はcors_plugを使ってみます。

  defp deps do
    [# ...,
     {:phoenix_swagger, path: "/path/to/phoenix_swagger"},
     {:cors_plug, "~> 1.1"}]
  end

依存関係のインストールはもうお分かりですね?

$ mix deps.get

READMEにしたがってweb/router.exを編集しましょう。

  pipeline :api do
    # originの値は実行するサーバのIPアドレスやDNS名など適切に設定します
    plug CORSPlug, [origin: "http://example.com"]
    plug :accepts, ["json"]
  end
  # ...
  scope "/", SwaggerSampleApp do
    pipe_through :api
    resources "/samples", SampleController, except: [:new, :edit]
    options "/samples", SampleController, :options
    options "/samples/:id", SampleController, :options
  end

編集したらPhoenixを再起動します。

Swaggerの設定

次に、先ほど生成したswagger.jsonを編集しましょう。最後の方に、"host":"localhost:4000"と書かれていますので、この部分を"host":"example.com:4000"のように、Phoenixを実行しているサーバのDNS名またはIPアドレスに変更します。

SwaggerからAPIを実行する

さて、皆様はすでにSwaggerの画面上にある「Try it out!」というボタンにお気づきでしょう。ようやくこのボタンを押す時がやってきました。

f:id:glpgsinc:20160825195212p:plain

まあ、まだデータを登録していないので空の配列が帰ってくるのですが、つまりこうやって実際にAPIを叩くこともできるのですね。もちろんパラメタのあるAPIならパラメタを指定することもできるのですが、今回はここまでにしましょう。

さいごに

ガラパゴスでは、業務で使う技術だけでなく、いろいろな言語やツールを試してみちゃう仲間を大絶賛超募集しています。皆様の応募をお待ちしています。

RECRUIT | 株式会社ガラパゴス iPhone/iPad/Androidのスマートフォンアプリ開発

では、御機嫌よう。