こんにちは。西日本テクノロジー&イノベーション室の藤田です。 日々(技術的に)強くなりたいと言っている新卒3年目です。 弊社では名刺を入社した時に100枚、それ以降も部門名称が変わるたびに100枚ずつ支給されるのですが、入社してからもらった名刺は400枚になりました。来年には500枚になっているかもしれません。

この記事では、先日まで関わっていたサービス開発案件で蓄積されたノウハウとして、Swaggerで生成したmockサーバーを使ってUI開発をする流れを書いていきます。

背景

3人チームで新規サービスを開発していました。

APIはRuby on Rails、UIはReactを使っており、私はUI開発者として参画しました。

今回の開発では、API開発を待たずともUIの開発ができるよう、Swaggerを使って生成したmockサーバーを使ってUI開発を行いました。

ここではSwaggerを使ってAPI仕様を定義し、API仕様からmockサーバーを生成してUI開発をする流れを共有します。

使ったもの

Swagger Editor

JSONまたはYAMLでAPI仕様を定義できます。プレビュー機能があり、構文間違いを都度チェックできるエディタです。オンラインのものもありますが、今回はDockerイメージを使用しました。 Swagger Codegen

API仕様を定義したYAMLファイルからmockサーバーを作ってくれます。こちらもDockerイメージを使用しました。

開発の流れ

1.DockerでSwagger Editorを立ち上げる

Docker Hubにイメージがあります。

swaggerapi/swagger-editor

今回はポート9200から繋げるように立ち上げました。

docker pull swaggerapi/swagger-editor
docker run -d -p 9200:8080 swaggerapi/swagger-editor

サンプルとしてSwagger PetStoreのAPI仕様が入っています。

2.API仕様を定義する

APIの開発者と認識を合わせながらAPI仕様を定義します。

先ほど立ち上げたSwagger Editorを使ってAPI仕様を書きます。今回はYAMLで書きました。

サンプルがエディタに入っているので、書き方が全くわからないということはありませんでしたが、細かいOpen APIの文法についてはOpenAPI Specificationを参照しました。

3.開発用mockサーバーを作成する

API仕様ができたら、開発用mockサーバーを作ります。mockサーバーの生成にはSwagger CodegenのDockerイメージを使いました。

カレントディレクトリにswagger.ymlを置いて、生成したmockサーバーを置くディレクトリmockを作った状態で以下のコマンドを叩くと、mockディレクトリ配下にmockサーバーが出力されるはずです。

docker run --rm -v `pwd`:/work swaggerapi/swagger-codegen-cli generate -l nodejs-server -i /work/swagger.yml -o /work/mock

UI開発にReactを使っているので、Reactが動く環境であれば特に手を加えることなく動かせるnodejs-serverを選びました。

サーバーポートはYAMLの host で指定できます。以下のYAMLだと、mockサーバーがlocalhost:3000で起動します。

swagger: "2.0"
info:
  title: "お菓子"
  description: "お菓子を返すAPI"
  version: 1.0.0
basePath: "/api"
tags:
- name: "item"
  description: "商品"
host: localhost:3000

4.mockを動かして開発する

3で作ったmockサーバーを yarn install yarn startしてUIの開発に着手します。

例えば商品IDを指定して商品の詳細情報が欲しい場合、Swaggerで以下の通り定義していたとします。

paths:
  /items/{item_id}:
    get:
      tags:
      - "item"
      summary: "商品の詳細を返す"
      produces:
      - "application/json"
      parameters:
      - in: "path"
        name: "item_id"
        type: "integer"
        required: true
      responses:
        200:
          description: "リクエストが成功した場合"
          schema:
            $ref: "#/definitions/Item"
        404:
          description: "指定された商品が見つからない場合"
definitions:
  Item:
    description: "商品の詳細情報"
    type: object
    properties:
      name:
        type: "string"
      description:
        type: "string"
      category:
        type: "string"
      price:
        type: "integer"
        description: "金額"
    example:
      name: "ブラックサンダー"
      description: |-
        みんな大好きブラックサンダーが装い改め新登場!
        1994年の発売から20年以上愛されている「ブラックサンダー」が2003年のパッケージ変更から14年ぶりにフルリニューアル!
        チョコレートとビスケットのバランスを見直し、カバーチョコレートを増量!
      category: "チョコレート"
      price: 30

React側で以下のようにAPIを叩くと、JSONが返ってくるはずです。

ちなみに、YAMLでitem_idのtypeをintegerと定義しているので、idにinteger以外を指定するとエラーになります。ただ、mockなので指定するidはintegerである限り何を指定しても同じJSONが返ってきます。

 async getItem(id) {
    const resp = await axios.get(`/api/items/${id}`)
    return resp.data;
  }
{
  "name": "ブラックサンダー",
  "description": "みんな大好きブラックサンダーが装い改め新登場!\n1994年の発売から20年以上愛されている「ブラックサンダー」が2003年のパッケージ変更から14年ぶりにフルリニューアル!\nチョコレートとビスケットのバランスを見直し、カバーチョコレートを増量!",
  "category": "チョコレート",
  "price": 30
}

JSONの中身は、YAMLでexampleに設定した値です。

exampleの設定方法は公式ドキュメントにある通り色々ありますが、今回はItemというModelにexampleを定義しました。Modelでexampleを定義せず、個々のレスポンスにexampleを定義することも可能ですが、複数のAPIで同じModelのレスポンスが欲しい場合にexampleごとModelを使いまわせるよう、Modelにexampleを定義しています。

これで、API開発を待たずとも正常系を確認できる環境が整いました。

使ってみて感じたこと

良かった点

Swagger Editorが使いやすい Swagger Editorにはプレビュー機能がついているので、構文間違いがないか都度チェックできて便利でした。

また、プレビュー機能のおかげで、API仕様の共有を開発者間でスムーズにできました。

UI開発とAPI開発を独立して行えた

当初の目的が達成できました。mockの生成方法が簡単なので、特に手間取ることなくUI開発を進めることができました。

不便に感じた点

Swagger Editorで構文エラーが起きると入力補完が一切効かなくなる

入力補完がきかなくなるとだいぶしんどいです。

Modelにexampleを定義する場合、そのModelの配列は各要素に異なる値を使用できない

今回Modelにexampleを定義していますが、exampleは1つのModel定義につき1つしか定義できない制約があります。この制約によって、同じModelが要素となる配列に対して、異なるサンプル値を設定できません。

例えば、あるカテゴリの商品を取得するAPIがあったとします。このAPIは、ItemというModelから成るオブジェクトを要素とする配列を返します。

paths:
  /categories/{category_id}/items:
    get:
      tags:
      - "item"
      summary: "あるカテゴリに属する商品一覧を返す"
      produces:
      - "application/json"
      parameters:
      - name: "category_id"
        in: "path"
        required: true
        type: "integer"
      responses:
        200:
          description: "成功時のレスポンス"
          schema:
            type: array
            items:
              $ref: '#/definitions/Item'
        404:
          description: "商品が見つからない場合"

Itemは次のように定義されています。

definitions:
  Item:
    description: "商品の詳細情報"
    type: object
    properties:
      name:
        type: "string"
      description:
        type: "string"
      category:
        type: "string"
      price:
        type: "integer"
        description: "金額"
    example:
      name: "ブラックサンダー"
      description: |-
        みんな大好きブラックサンダーが装い改め新登場!
        1994年の発売から20年以上愛されている「ブラックサンダー」が2003年のパッケージ変更から14年ぶりにフルリニューアル!
        チョコレートとビスケットのバランスを見直し、カバーチョコレートを増量!
      category: "チョコレート"
      price: 30

1つのModel定義につき1つのexampleしか定義できないので、配列に入るサンプル値も1種類しかないことになります。上の例でいうと、/categories/:id/items で返ってくる配列の要素にはブラックサンダーしかないことになります。

mockサーバーを作った目的はUI開発のためのデータ取得です。UI開発をしていたら、表示対象のデータを色々なもので試したくなるはずです。画像サイズ、縦横比、タイトルの文字数など、色々な種類のデータを入れて見た目を調整したくなります。

しかし、Modelに定義できるexampleは1種類なので、データは1種類しか扱えません。これはUI開発をするにあたり不便に感じました。

おわりに

Swaggerを使ってmockサーバーを生成してUI開発をした流れを書いてみました。

API仕様の共有が開発者間でスムーズにできた点、UI開発とAPI開発を独立して行える点は非常によかったです。 不便に感じた点はあるものの、mockが簡単に生成できる点はかなり魅力的なので、今後もUIとAPIを独立して開発したい時はSwaggerを使おうと思います。


本コンテンツはクリエイティブコモンズ(Creative Commons) 4.0 の「表示—継承」に準拠しています。