RailsのAPIをswaggerでドキュメント化してみる

最近Railsを使用してAPIを作成することが多いのですが、静的にドキュメントにリクエストパラメータが〇〇で、レスポンスが□□で...の用に書くのがたるくなってきたので、何か良いツールが無いかと探していた所、`Swagger`というツールを見つけました。

## Swaggerについて

[公式サイト](http://swagger.io)

APIのパス、説明、リクエストパラメータ、レスポンス等を記述したJSONファイルを、Swaggerを使用することで、Web上で、インタラクティブにRestfulAPIの動作確認も行えるOSSです。

![swagger.png](https://qiita-image-store.s3.amazonaws.com/0/20424/a30e6bfc-b95d-b9bf-cfcf-e1f78e828773.png)

現行バージョンは2.0で、こちらについては、Web上でymlを記載するだけで生成してくれるエディターが存在します。

http://editor.swagger.io#/

## Railsで作成したAPIに対してSwaggerを使用する

RailsでSwaggerのJSONを生成する場合、いくつかの方法があります。

- `grape-swagger`というgemでgrapeの記法で使用する
- `swagger-docs`というgemでRailsのコントローラ、ルーティングを動的にJSONにパースする(しかし1.2しか対応していない)
- `ruby-swagger`というgemで頑張る(多分これを使うくらいなら上記のエディタの方が楽)

それで、今回は既存のRailsのRestfulAPIに対してドキュメントを記載したかったため、`swagger-docs`を採用しました。

## swagger-docs

### インストール

Gemfileに以下を追記します

```ruby:Gemfile
# grapeは使用しないが、中にswagger-uiのassets一式が入っているので、viewに利用
gem 'grape-swagger-rails', '~> 0.3.0' 
gem 'swagger-docs', '~> 0.2.9'
```

### 設定

initializers以下に追加して、初期化時に読み込ませます

```ruby:swagger_docs.rb
# Swagger settings
# baseのcontrollerの指定、変換パスの設定
class Swagger::Docs::Config
  def self.base_api_controller; ActionController::API end
  def self.transform_path(path, api_version); "apidocs/#{path}" end
end

# 出力JSON設定
Swagger::Docs::Config.register_apis({
  "v1" => {
    :api_extension_type => nil,
    :api_file_path => "public/apidocs/", # JSONが置かれるPATH
    :base_path => "http://localhost:3000/", # 最後の`/`が置換されてしまうのでURLを記載
    :clean_directory => true,
    :formatting => :pretty,
    :camelize_model_properties => false,
    :controller_base_path => "",
    :attributes => {
      :info => {
        "title"       => "Books API",
        "description" => "Books operation API",
        "contact"     => "tora.1986.tatsu@gmail.com",
        "license"     => "Apache 2.0",
        "licenseUrl"  => "http://www.apache.org/licenses/LICENSE-2.0.html"
      }
    }
  }
})

GrapeSwaggerRails.options.app_name    = "Books API"
# 基盤となるJSON
GrapeSwaggerRails.options.url         = "/apidocs/api-docs.json"
# こっちの`/`は置換されないのでこれでOK
GrapeSwaggerRails.options.app_url     = "/"
```

#### Routing

config/routes.rbに以下を追加

```ruby:routes.rb
  mount GrapeSwaggerRails::Engine => "/swagger"
```

#### assets

JS,CSSの読み込みを追記

- app/assets/javascripts/application.js

```javascript:application.js
//
//= require_tree .
```

- app/assets/stylesheets/application.css

```css:application.css
/*
 *= require_tree .
 */
```

### controllersにswagger-docsの記述を追加

#### controllerの指定

`swagger_controller :controller名, "説明"`

controller名を指定します。指定したcontroller名から動的にルーティング情報を読み込んでくれます。

```ruby
  swagger_controller :Books, "Book"
```

#### apiの指定

Routingのpathを指定することで、JSONに出力するpathを指定できます。

`swagger_api :path名 do ~ end`

```ruby
  swagger_api :show do
    summary "Get a book"
    consumes [ "application/json" ]
    param :path, :id, :integer, :required, "Book Id"
    response :ok, "Success", :Book
    response :not_found
    response :internal_server_error
  end
```

- summary : APIのサマリー
- consumes : Content-Type
- param : パラメータ指定
  - header : ヘッダー
  - path : URL path
  - form : FORMパラメータ
  - body : JSON Body
- response : レスポンス(Rackの識別名が使用できる)

#### モデルオブジェクトの指定

Railsのモデルとは別で、swagger自体にモデルオブジェクトの記述方法が存在しており、これは、レスポンスのExampleや、パラメータにJSONを指定したいときに呼び出して使うことが出来ます。

`swagger_model :モデル名 do ~ end`

```ruby
  swagger_api :create do
    summary "Create a book image"
    consumes [ "application/json" ]
    param :body, :body, :object, :required, "Book image parameters", { "$ref": "BookImage" }
    response :ok, "Success", :BookImage
    response :not_found
    response :internal_server_error
  end

  
  swagger_model :BookImage do
    description "Book a object"
    property :id, :integer, :required, "Book image Id"
    property :book_id, :integer, :required, "Book Id"
    property :url, :string, :required, "Book image URL"
    property :alt, :string, :required, "Book image alt"
  end
```

- description : モデルの説明
- property : モデルのプロパティ

記載したモデルを`swagger_api`ブロック内の`response`の第3引数に渡すことで、アウトプットJSONのサンプルに指定できたり、`param`の第6引数はハッシュ形式で渡すことが可能なので、`{ "$ret": "Model" }` と指定することで、パラメータをJSON形式で渡すことが出来るようになります。

その他の詳細な書き方については、出力されたJSONを公式のドキュメントと見比べて行くといいと思います。

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/1.2.md

### JSONの生成

swagger-docsの形式で記述ができたら、swagger形式のJSONを生成するために下記のRakeタスクを実行します。

```console
$ rake swagger:docs
```

public以下にswaggerの設定で指定したディレクトリが作成されていれば成功です。
起動して確認してみましょう。

```console
$ rails s
```

http://localhost:3000/swagger/

今回作成したサンプルです。

https://github.com/kitaro-tn/swagger-sample-books