プロジェクトに API 仕様書を導入したい話

メリークリスマス:christmas_tree::christmas_tree:
CBcloud アドベントカレンダー最後を担当する hiracky16 です。

せっかくクリスマスの担当なのでクリスマスネタで書きたかったのですが、何も思い浮かびませんでした。

今回は現プロジェクトに API 仕様書の導入を考えているのでその構想を前職での経験を踏まえつつ書いていきたいと思います。

## 今まで書いていた API 仕様書

### ツール・運用

前職では API BluePrint に準拠して仕様書を記述していました。
もともと使っていたため導入理由は知りませんが、使う利点として以下が挙げられます。

- Markdown 形式で記述できるため学習コストが少ない
- コード管理できる
- 仕様書のデザインがイケてる

どうイケてるかというとこんな感じです。
メソッドごとに色分けされおり、視覚的にわかりやすい。
また左側のメニューにある通りリソースごとに操作をまとめることができ、引くときに便利です。

仕様書のレンダリングには [aglio](https://github.com/danielgtaylor/aglio) という npm パッケージを使っていました。
これを使うとコマンド一発で仕様書を html 形式で出力してくれるためメンバー間での共有も楽です。

![スクリーンショット 2019-12-21 10.41.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119099/3752e5e3-6d3d-d84a-157d-daead98bbc68.png)

### 気をつけていたこと

まあ当然ですが、すごくわかりやすく書いていました。
特にオペレーション上 REST に準拠していないエンドポイントを生やさなけれなならない場合（`{リソース名}/{動詞}` みたいなやつ）、
何をするものなんか、成果物はなにか事細かく書いていました。

またリソースを新しく足すときやそれに対する操作を加える際に言葉選びには注意をしていました。
[codic](https://codic.jp/) とか使うといい感じに命名できるので活用していました。


## これから書きたい API 仕様書

前職で書いていた API 仕様書は最低限のことはできていたと思います。
上記のことを守りつつ仕様書からのコード生成やテストの実行などが加えてできる仕様書を目指します。
また現状の開発速度を落とさずに導入することも重要です。

これらの観点と現プロジェクトとの相性で調べていたところ Swagger にたどり着きました。

### Open API と Swagger

Open API は API BluePrint と同じく API を書く際のフォーマットのことです。
BluePrint と大きく違う点は YAML か JSON で記述することや API Gateway や Cloud Endpoint へそのままインポートすることが可能な点が挙げられます。

また Swagger を使うと Open API 容易に作成することができ、かつコードの自動生成やテストの実行などが可能です。
Swagger は Open API を書くためのツール群のことを指します。
以下の 2 つのツールを使うと Open API に準拠した仕様書が作れます。
また Dredd というツールを使うと仕様書ベースで API へのテストを実行できます。

- [Swagger Editor](http://editor.swagger.io/) ... ブラウザで Open API を記述することができるツール、プレビューしてくれるところが良い
- [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) ... Open API の仕様書からコード生成するためのツール
- [Dredd](https://github.com/apiaryio/dredd) ... API 仕様書からテストするツール、（もともと API Blueprint の方に対応していたが Swagger にも対応済み）

### プロジェクトへの適応

導入先として Rails + Grape を使ったプロジェクトを考えます。
（プロジェクトは検証用に適当に作ったものなので無視してください）

#### コードから仕様書を生成

すでに存在する API から仕様書が作成できないか調べたところ、
swagger-grape という gem を使えばものの 3 分くらいでできました。
とりあえず仕様書作るだけなら Open API 書かなくても大丈夫。

![スクリーンショット 2019-12-22 17.23.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119099/14f8cf58-8b10-ff3d-bb87-69b419b36e1d.png)

#### テスト実行

上で生成した生成した yaml or json を元に API サーバーにリクエストするテストを前述の Dredd で実行したところ、
パスに含まれるパラメータの例などが記述されていなかったためそのままだと通りませんでした。

テスト実行させるには以下の操作が必要です。
まず Grape Entity にドキュメントを追加していきます。

```ruby:gruop_entity.rb
module V1
  module Entities
    class GroupEntity < Grape::Entity
      expose :id, documentation: { type: 'integer', required: true }  # doc 追加
      expose :name, documentation: { type: 'string', required: true } # doc 追加
    end
  end
end
```

コントローラーの方にもドキュメントを追加していきます

```ruby:groups.rb
module V1
  class Groups < Grape::API
    resources :groups do
      desc 'returns all groups', {
        is_array: true,
        success: V1::Entities::GroupEntity
      }                                     # 追加
      get '/' do
        @groups = Group.all
        present @groups, with: V1::Entities::GroupEntity
      end
  ...
```

すると仕様書に Model の枠ができて Entity の内容が記載されます。

![スクリーンショット 2019-12-24 8.12.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119099/470d95e1-15f5-a0d4-d74d-c04b0d833d59.png)

Entity も増えると厄介なのでここで見れるのは嬉しい。
次に yaml なり json ファイルを生成したあとに、デフォルトパラメータを記述します。

```yaml:api.yaml
paths:
  '/v1/groups/{id}':
    get:
      description: returns a group
      produces:
        - application/yaml
      parameters:
        - in: path
          name: id
          type: integer
          format: int32
          required: true
          default: 1   # 追加
      responses:
        '200':
          description: returns a group
          schema:
            $ref: '#/definitions/GroupEntity'
      tags:
        - groups
      operationId: getV1GroupsId
```

そして、テスト実行！
テスト実行はこんな感じでコマンドベースでできるため自動化できそう。

```shell
$ dredd api.yml http://localhost:3000
```

RSpec があるのでちゃんとしたテストはいらないかもですが、
仕様書を書くだけで TDD っぽく開発できるのでは！となりました。

#### 仕様書執筆環境

なれたら直接 yaml や json ファイルを直接いじって仕様書作成！となりそうですが、ハードル高そうなので Swagger Editor を使いたい。
Swagger Editor の [Docker イメージ](https://hub.docker.com/r/swaggerapi/swagger-editor/) が配布されていたため、それを使って書くことができました。

ここらへん Blueprint だと markdown で記述できるため、柔軟に仕様書をかけていたなーと良さを実感しました。

#### 仕様書からコードを生成

swagger-codegen を使うとできます。（上で立ち上げた Swagger Editor の上部メニューからも生成可能）

結果、Grape を使った形で出てこないため、成果物を使ってそのまま開発はできないです。

ただ、モックとしては使えそうなので、仕様書しかできていない場面でクライアントサイドにとって便利かも。

## まとめ

長々とこれから API 仕様書を書くぞという強い気持ちを示しました。
とりあえず Swagger を使って現コードの仕様書を作るところから始めようと思います。

Swagger には他にも便利そうなツールがありそうなので都度調べて取り入れていけたらと思いました。

それではみなさん良いお年を！ :bamboo: