2018年7月21日土曜日

flasgger で APISpec を使ってコードから swagger.yml を生成する方法

概要

flasgger は内部的に apispec を使っています
apispec は OpenAPI-Specification ベースの定義ファイルをコードから生成することができるモジュールです
今回は flasgger 上のコードから apispec の機能を使って swagger の定義ファイルを生成してみました

環境

  • macOS X 10.13.6
  • Python 3.6.5
  • flasgger 0.9.0
  • apispec 0.38.0

インストール

  • pipenv install flasgger marshmallow apispec=="0.38.0"

サンプルコード

  • vim test_apispec.py
# coding: utf-8
from flask import Flask, jsonify

from flasgger import APISpec, Schema, Swagger, fields

# Create an APISpec
spec = APISpec(
    title='Flasger Petstore',
    version='1.0.10',
    plugins=[
        'apispec.ext.flask',
        'apispec.ext.marshmallow',
    ],
)

app = Flask(__name__)


class CategorySchema(Schema):
    id = fields.Int()
    name = fields.Str(required=True)


class PetSchema(Schema):
    category = fields.Nested(CategorySchema, many=True)
    name = fields.Str()


@app.route('/random')
def random_pet():
    """A cute furry animal endpoint.
    ---
    get:
        description: Get a random pet
        responses:
            200:
                description: A pet to be returned
                schema:
                    $ref: '#/definitions/Pet'
    """
    pet = {'category': [{'id': 1, 'name': 'rodent'}], 'name': 'Mickey'}
    return jsonify(PetSchema().dump(pet).data)

template = spec.to_flasgger(
    app,
    definitions=[CategorySchema, PetSchema],
    paths=[random_pet]
)
swag = Swagger(app, template=template)

print(spec.to_dict())
print(spec.to_yaml())

if __name__ == '__main__':
    app.run(debug=True)

最後の print 文 2 つで dictionary 形式と YAML 形式の定義ファイルを出力しています

説明

最初に APISpec を使ってメタデータなどを定義します
plugings は定義ファイルには表示されませんが必須です

spec = APISpec(
    title='Flasger Petstore',
    version='1.0.10',
    plugins=[
        'apispec.ext.flask',
        'apispec.ext.marshmallow',
    ],
)

その後に definitions 用のクラスの定義と paths に応じた処理が書いてあります
そしてその次に spec に対して定義した definitions と paths を登録します

template = spec.to_flasgger(
    app,
    definitions=[CategorySchema, PetSchema],
    paths=[random_pet]
)

更にその後で swag = Swagger(app, template=template) という設定がありますがこれは /apidocs を表示するための設定なのでなくても問題ないです

動作確認

  • pipenv run python3 test_apispec.py

  • curl http://localhost:5000/random

という感じでリクエストすると動作します
また、サーバを動作させたターミナル上で dictionary と YAML の定義情報が表示されているのがわかると思います

definitions:
  Category:
    properties:
      name: {type: string}
      id: {format: int32, type: integer}
    required: [name]
    type: object
  Pet:
    properties:
      name: {type: string}
      category:
        items: {$ref: '#/definitions/Category'}
        type: array
    type: object
info: {title: Flasger Petstore, version: 1.0.10}
parameters: {}
paths:
  /random:
    get:
      description: Get a random pet
      responses:
        200:
          description: A pet to be returned
          schema: {$ref: '#/definitions/Pet'}
swagger: '2.0'
tags: []

今回の定義だと上記のような感じで表示されると思います

最後に

flasgger の APISpec の機能を使ってコードから swagger ファイルを出力してみました
おそらくこれがあるのは swagger ファイルからモデルを生成するのではなくコードから swagger ファイルを生成したいという需要があるからだと思います
普通に考えれば swagger-codegen などを使ってコードを生成しますが、それだと内部がブラックボックスなのと結局コードと swagger ファイルをメンテンスしなければならないので、それであればコードだけを書き続けて swagger ファイルを自動生成するほうが良いということなんだと思います

参考サイト

0 件のコメント:

コメントを投稿