エンジニア

2015.11.26

Swaggerで作るSPECファイルを小さいファイルに分割する

Swaggerで作るSPECファイルを小さいファイルに分割する

こんにちは、井上です。

Swaggerで始めるモデルファーストなAPI開発」を見て興味を持ったので、Swaggerをちょっと触ってみたのですが、すぐに、これ1ファイルの YAMLファイルでメンテナンスするの超しんどくない?と感じました。

なので、分割する方法を調べてみました。で、みつけたのが下記エントリ。
How to split a Swagger spec into smaller files

方法としては、別々のファイルに書いた定義を $ref で参照しておき、それを json-refs でマージして1ファイルに戻すというやり方のようです。

下記のような YAML ファイルを、

swagger: '2.0'
info:
  version: 0.0.0
  title: Simple API
paths:
  /foo:
    get:
      responses:
        '200':
          description: OK
  /bar:
    get:
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/User'
definitions:
  User:
    type: object
    properties:
      name:
        type: string

下記のように分割します。

$ tree
.
├── README.md
├── definitions
│   ├── User.yaml
│   └── index.yaml
├── index.yaml
├── info
│   └── index.yaml
├── package.json
├── paths
│   ├── bar.yaml
│   ├── foo.yaml
│   └── index.yaml
└── resolve.js

起点となる index.yaml は下記のようにリンク集のような形になります。

swagger: '2.0'
info:
  $ref: ./info/index.yaml
paths:
  $ref: ./paths/index.yaml
definitions:
  $ref: ./definitions/index.yaml

サンプルが githubに上がっているので、それで試してみます。

$ git clone https://github.com/mohsen1/multi-file-swagger-example.git
$ cd multi-file-swagger-example
$ npm install
$ node resolve.js
{
  "swagger": "2.0",
  "info": {
    "version": "0.0.0",
    "title": "Simple API"
  },
  "paths": {
    "/foo": {
      "get": {
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/bar": {
      "get": {
        "responses": {
          "200": {
            "description": "OK",
            "schema": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "definitions": {
    "User": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      }
    }
  }
}

全部マージして出力されました。

JSON形式になっていますが、resolve.js を下記のような感じに変更すると、YAML 形式で出力されます。
※ js-yaml が必要なので、別途 npm install js-yaml が必要です。

var resolve = require('json-refs').resolveRefs;
var YAML = require('js-yaml');
var fs = require('fs');
var root = YAML.load(fs.readFileSync('index.yaml').toString());
var options = {
  processContent: function (content) {
    return YAML.load(content);
  },
  resolveLocalRefs: false
};
resolve(root, options).then(function (results) {
  console.log(YAML.dump(results.resolved));
});
$ node build.js
swagger: '2.0'
info:
  version: 0.0.0
  title: Simple API
paths:
  /foo:
    get:
      responses:
        '200':
          description: OK
  /bar:
    get:
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/User'
definitions:
  User:
    type: object
    properties:
      name:
        type: string

オプションに、resolveLocalRefs: false を加えると、ファイル内の $ref: ‘#/definitions/User’ は展開されず、別ファイルのみ展開されます。
同じ定義を繰り返し参照しているような場合には、展開しないほうが見通しが良いと思います。

使用できるオプションは、下記で参照できます。
json-refs/API.md at master · whitlockjc/json-refs

一覧に戻る