21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

swagger-merger + ReDoc + DockerでAPIドキュメントを作る

Posted at

やりたいこと

  • 最近の開発でSwaggerを使ってAPI定義を書くことが多いが、APIが増えてくるとSwaggerが肥大化して辛いのでファイルを分割管理したい!
  • 複数のAPIを1ファイルに定義した場合にswagger-uiのGUIだとちょっと見にくいなーと感じたので
    イカした見た目で確認できるようにしたい!

やらないこと

  • CI
    • ここはとりあえずdockerで確認できるところまで

登場人物の概要

OpenAPI

  • 正式名称はOpenAPI-Specification(OAS)
  • OpenAPI Initiative(OAI)というコミュニティによって定義されているRESTful APIの標準仕様
  • JSON/YAML形式で作成可能

Swagger

  • OpenAPI仕様に基づいて構築されたオープンソースツールのセット
  • 主要ツール
    • Swagger Editor
    • Swgger UI
    • Swagger Codegen

swagger-merger

  • 複数のswaggerファイルを一つのswaggerにまとめて出力してくれるスゴイやつ
  • JSON/YAMLのどちらでもOK
  • OpenAPI 3.0にも対応してる

ReDoc

  • swaggerをイカした見た目で表示できるスゴイやつ
  • OpenAPI 3.0にも対応してる

OpenAPIドキュメントを作る

1から自分で作るのが面倒なので 今回はOAIにある以下のサンプルを使って分割・ReDocを試してみます。
https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/uspto.yaml

エンドポイントは3つですが1ファイルで200行を超えています。

swaggerファイルを分割する

実際のプロジェクトで使うときはもう少し細かく分けたほうが良いと思いますが、
とりあえず今回は以下の構成にしてみます。

.
├── components
│   ├── index.yml
│   └── schemas
│       └── index.yml
├── index.yml
└── paths
    ├── index.yml
    ├── metadata
    │   ├── fields.yml
    │   └── index.yml
    └── search
        └── records.yml

ルートファイルの記述

index.ymlがルートファイルになります。
ここでは$refを使用してpathsとcomponentsの各ディレクトリのindex.ymlの読み込みを行っています。

openapi: 3.0.1
servers:
  
info:
  
tags:
  
paths:
  $ref: "./paths/index.yml"
components:
  $ref: "./components/index.yml"

※pathsとcomponents以外はexampleの内容のままなので省略しています。

pathsの記述

paths/index.ymlでは各エンドポイントごとにyamlファイルを読み込みを行います。

/:
  $ref: "./metadata/index.yml"
/{dataset}/{version}/fields:
  $ref: "./metadata/fields.yml"
/{dataset}/{version}/records:
  $ref: "./search/records.yml"

paths/metadata/index.ymlの内容は以下。(サンプルのコピペ)

/:
  get:
    tags:
      - metadata
    operationId: list-data-sets
    summary: List available data sets
    responses:
      '200':
        description: Returns a list of data sets
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/dataSetList'
            example:
              {
                "total": 2,
                "apis": [
                  {
                    "apiKey": "oa_citations",
                    "apiVersionNumber": "v1",
                    "apiUrl": "https://developer.uspto.gov/ds-api/oa_citations/v1/fields",
                    "apiDocumentationUrl": "https://developer.uspto.gov/ds-api-docs/index.html?url=https://developer.uspto.gov/ds-api/swagger/docs/oa_citations.json"
                  },
                  {
                    "apiKey": "cancer_moonshot",
                    "apiVersionNumber": "v1",
                    "apiUrl": "https://developer.uspto.gov/ds-api/cancer_moonshot/v1/fields",
                    "apiDocumentationUrl": "https://developer.uspto.gov/ds-api-docs/index.html?url=https://developer.uspto.gov/ds-api/swagger/docs/cancer_moonshot.json"
                  }
                ]
              }

paths/metadata/fields.ymlの内容は以下。(サンプルのコピペ)

/{dataset}/{version}/fields:
  get:
    tags:
      - metadata
    summary: >-
      Provides the general information about the API and the list of fields
      that can be used to query the dataset.
    description: >-
      This GET API returns the list of all the searchable field names that are
      in the oa_citations. Please see the 'fields' attribute which returns an
      array of field names. Each field or a combination of fields can be
      searched using the syntax options shown below.
    operationId: list-searchable-fields
    parameters:
      - name: dataset
        in: path
        description: 'Name of the dataset.'
        required: true
        example: "oa_citations"
        schema:
          type: string
      - name: version
        in: path
        description: Version of the dataset.
        required: true
        example: "v1"
        schema:
          type: string
    responses:
      '200':
        description: >-
          The dataset API for the given version is found and it is accessible
          to consume.
        content:
          application/json:
            schema:
              type: string
      '404':
        description: >-
          The combination of dataset name and version is not found in the
          system or it is not published yet to be consumed by public.
        content:
          application/json:
            schema:
              type: string

paths/search/index.ymlの内容は以下。(サンプルのコピペ)

/{dataset}/{version}/records:
  post:
    tags:
      - search
    summary: >-
      Provides search capability for the data set with the given search
      criteria.
    description: >-
      This API is based on Solr/Lucense Search. The data is indexed using
      SOLR. This GET API returns the list of all the searchable field names
      that are in the Solr Index. Please see the 'fields' attribute which
      returns an array of field names. Each field or a combination of fields
      can be searched using the Solr/Lucene Syntax. Please refer
      https://lucene.apache.org/core/3_6_2/queryparsersyntax.html#Overview for
      the query syntax. List of field names that are searchable can be
      determined using above GET api.
    operationId: perform-search
    parameters:
      - name: version
        in: path
        description: Version of the dataset.
        required: true
        schema:
          type: string
          default: v1
      - name: dataset
        in: path
        description: 'Name of the dataset. In this case, the default value is oa_citations'
        required: true
        schema:
          type: string
          default: oa_citations
    responses:
      '200':
        description: successful operation
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                additionalProperties:
                  type: object
      '404':
        description: No matching record found for the given criteria.
    requestBody:
      content:
        application/x-www-form-urlencoded:
          schema:
            type: object
            properties:
              criteria:
                description: >-
                  Uses Lucene Query Syntax in the format of
                  propertyName:value, propertyName:[num1 TO num2] and date
                  range format: propertyName:[yyyyMMdd TO yyyyMMdd]. In the
                  response please see the 'docs' element which has the list of
                  record objects. Each record structure would consist of all
                  the fields and their corresponding values.
                type: string
                default: '*:*'
              start:
                description: Starting record number. Default value is 0.
                type: integer
                default: 0
              rows:
                description: >-
                  Specify number of rows to be returned. If you run the search
                  with default values, in the response you will see 'numFound'
                  attribute which will tell the number of records available in
                  the dataset.
                type: integer
                default: 100
            required:
              - criteria

componentsの記述

components/index.ymlはpathsと同様にサブディレクトリのindex.ymlを読み込んでいます。

schemas:
  $ref: "./schemas/index.yml"

components/schemas/index.ymlの内容は以下。(サンプルのコピペ)

dataSetList:
  type: object
  properties:
    total:
      type: integer
    apis:
      type: array
      items:
        type: object
        properties:
          apiKey:
            type: string
            description: To be used as a dataset parameter value
          apiVersionNumber:
            type: string
            description: To be used as a version parameter value
          apiUrl:
            type: string
            format: uriref
            description: "The URL describing the dataset's fields"
          apiDocumentationUrl:
            type: string
            format: uriref
            description: A URL to the API console for each API

swaggerファイルをマージする

swagger-mergerをインストール

ファイルの分割が終わったのでswagger-mergerの出番です!!
npmで簡単にインストールできます!

$ npm install --dev swagger-merger

マージ!

今回はグローバルにインストールしていないので相対パスでファイル指定して実行します。
npm scriptsに設定するとかすると楽だと思います。

$ ./node_modules/.bin/swagger-merger -i index.yml -o swagger.yml

これで分割て作成したYAMLがswagger.ymlにマージされて出力されます!

swagger-uiで確認する

dockerで簡単にswagger-uiの環境を構築できるので、サクッと動かします。

docker-compose.ymlを以下のようにします

version: "3"

services:
  swagger-ui:
    image: swaggerapi/swagger-ui
    ports:
      - 8080:8080
    volumes:
      - ./swagger.yml:/usr/share/nginx/html/swagger.yml
    environment:
      API_URL: swagger.yml

起動&確認

$ docker-compose up -d --build
$ open http://localhost:8080

よく見るswagger-uiの画面が確認できます!

localhost_8080_.png

ReDoc

APIが数本だとswagger-uiでも特に困らないのですが、APIが増えた時にswagger-uiだとちょっと見にくいなーと感じました。
そこでReDocというSwaggerをイカした見た目にできるツールを使ってみたいと思います。

dockerで動かすだけなら非常に簡単で、以下をdocker-compose.ymlに追記するだけです。

  redoc:
    image: redocly/redoc
    ports:
      - 8081:80
    volumes:
      - ./swagger.yml:/usr/share/nginx/html/swagger.yml
    environment:
      SPEC_URL: swagger.yml

動作確認

$ docker-compose up -d --build
$ open http://localhost:8081

localhost_8081_ (1).png

なんかかっこよくなったぞ!!!!!!

おわり

今回はdockerを使ってローカルPCで確認するまでにしておきましたが
実際使うならCIに組み込んで公開まで行うとより捗るかと思います。

21
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?