swagger のモックモードと json-editor を絡めて両者を軽く試す

# swagger と json-editor

この二つ、両者とも直接の関係はない(と思う)のですがどちらも JSON Schema に関連するプロダクトです。

- [swagger](http://swagger.io)
    - API 定義及び API サーバ開発のための便利ツールが揃ったすごいコンポーネント群
- [json-editor](https://github.com/jdorn/json-editor)
    - JSON Schema からエディタを生成するライブラリ

今回は swagger で頑張って定義した API 仕様から手軽にデータの編集フォームを作れたりする技術はないかな、と調べていた過程で、なんとなく動作する例が見つかったのでここにまとめていきます。あとついでに swagger のモックモードも使ったことがなかったので試しに使ってみたかったのもあります。

がっつりとした開発は行いませんが、両者を軽く組み合わせて揉んでみる程度、「いちおう両方動いてる」感じを目標に進めていきます。swagger 定義をある程度書いたことのある人を対象にします。

# swagger で API 定義を書く

まずは今回の題材となる API 定義を適当に決めていきます。

プロジェクトを `swagger project create <some-project>` で生成し、`swagger project verify` しながらコツコツ定義を書いていきます。swagger には専用のエディタも用意されているのですが、起動するのが面倒だったので今回はエラーメッセージを見ながら手元のエディタで編集しました。

最終的に API のエンドポイント定義は以下のようになりました。本とコメントを登録する API のイメージです。

```yaml:swagger.yaml#/paths
paths:
  /books/{id}:
    x-swagger-router-controller: books
    parameters:
      - name: id
        in: path
        required: true
        type: string
    get:
      operationId: getBook
      responses:
        "200":
          description: Success
          schema:
            $ref: "#/definitions/Book"
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"
```

スキーマ定義は以下のようになります。定義間で参照される場合を試したかったので、コメントを配列形式にし、そのスキーマ定義を `Comment` として `Book` とは分けて定義してみました。後で用意する json-editor の表示で使われるようなので各フィールドの `title` をしっかりと定義しています。

```yaml:swagger.yaml#/definitions
definitions:
  Book:
    properties:
      title:
        title: Book Title
        type: string
      price:
        title: Price of the Book
        type: number
      comments:
        title: Comments
        type: array
        items:
          title: Comment
          $ref: "#/definitions/Comment"

  Comment:
    properties:
      date:
        title: Date
        type: string
        format: date
      score:
        title: Score
        type: number
      note:
        title: Note
        type: string
```

`swagger.yaml` 全体の定義は [lbcat/swagger-json-editor](https://github.com/lbcat/swagger-json-editor/blob/master/api/api/swagger/swagger.yaml) に置いておきました。

## モックモードで API サーバを起動する

API サーバを起動する際に `--mock` オプションをつけることで適当なデータを埋めて仕様に沿った最低限のデータを返すモックモードで起動します。

```
swagger project start --mock
```

試しに適当な ID を指定して `/books/:id` を叩いてみると、以下のように

```
tailmoon:api asa-taka$ curl -s localhost:10010/books/some-book | jq
{
  "title": "Sample text",
  "price": 1,
  "comments": [
    {
      "date": "2017-05-09",
      "score": 1,
      "note": "Sample text"
    }
  ]
}
```

文字列フィールドは `Sample text` 日付フィールドは現在時刻、配列は要素数 1 で埋められた、確かに仕様は満たしているモックデータが返ってきます。

ハマった点としては API 定義の `path` オブジェクトに `x-swagger-router-controller` を指定しておかないとモックデータは返ってこないという点です(https://github.com/swagger-api/swagger-node/issues/342 に関係しているのでしょうか、とりあえずコントローラの実態はなくとも指定しておけばモックとしては動作するので、ここでは詳しく追わないことにします)。

以上で、モックモードで起動したサーバはひとまず置いておいて、次は json-editor を利用した簡単な編集アプリを用意します。

# json-editor を利用した簡単な編集ページを用意する

以上の API 定義とは別プロジェクトで(という規模のものでもないのですが)編集アプリを用意します。利用するライブラリは json-editor のみなので、適当な方法で用意し静的な html で読みこんで動作させます。今回は `npm install json-editor` で取得しました。 

そこまでコード量も多くないので全部載せてしまいます。

```js:editor.js

// エディタを生成するための swagger 定義と編集対象のデータを取得します
Promise.all([
  
  // swagger 定義
  fetch('http://localhost:10010/swagger').then(res => res.json()),

  // Book のモックデータを得るための適当な ID を指定したパス
  fetch('http://localhost:10010/books/some-book').then(res => res.json()),
]).then(results => {

  // デストラクチャリング
  const [swg, data] = results;

  // swagger 定義を JSON Schema に変形
  const schema = {
    $ref: '#/definitions/Book',   // 目的のスキーマをルート直下から参照する
    definitions: swg.definitions, // 依存性解決のため swagger の definitions をごっそりそのまま持ってくる
  };

  // エディタ生成
  // 細かいオプションは https://github.com/jdorn/json-editor#options を参照
  const element = document.getElementById('editor-container');
  const editor = new JSONEditor(element, { schema, startval: data });

})
```

```html:editor.html
<!DOCTYPE html>
<html>
<head>
  <script src="node_modules/json-editor/dist/jsoneditor.js"></script>
</head>
<body>
  <div id="editor-container"></div>
  <script src="editor.js"></script>
</body>
</html>
```

ポイントは swagger の定義を一部書き換えて JSON Schema の仕様に沿った形に変形しているところです。こちらは特にサーバを用意する必要はないのでローカルのファイル `editor.html` を直接ブラウザで表示すると、以下の画面が表示されました。簡易的な見た目ですが一通りの機能は揃っています。

![Screen Shot 2017-05-10 at 0.14.39.png](https://qiita-image-store.s3.amazonaws.com/0/86904/43e67411-0041-6daf-8406-84c0408a9f74.png)

各フィールドにモックデータが反映され、それぞれのデータ型も適切に反映されているように見えます。配列形式のデータも適宜フィールドを追加できるようになっていますし、`#/definitions/Book` から `#/definitions/Comment` を参照しているところも問題なく表示されていますね。

json-editor には[生成時のオプション](https://github.com/jdorn/json-editor#options)に `refs` など、いろいろ気になる項目もあり、もしかしたらそれを利用すればもっと簡単に動作させることもできたかもしれませんが、ひとまず当初の目的である swagger のモックモードと json-editor をゆるく試す、という趣旨は満たされたかな、と思ったので今回はひとまず、ここまでです。

以上のコードは https://github.com/lbcat/swagger-json-editor に置いておきました。