2018年7月26日木曜日

flasgger + marshmallow schemas で validation と validation_function の挙動を確認してみた

概要

flasgger には validation の機能がデフォルトで備わっています
今回は validation 機能を使って挙動を確認してみました

環境

  • macOS X 10.13.6
  • Python 3.6.5
  • flasgger 0.9.0

サンプルアプリ

以下のサンプルアプリを元に挙動を確認します
POST のリクエストを受け取って処理する簡単なアプリです

# coding: utf-8
from flask import Flask, jsonify
from flasgger import Schema, Swagger, SwaggerView, fields


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


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


class RandomView(SwaggerView):
    parameters = [
        {
            'in': 'body',
            'name': 'Pet',
            'description': 'Register a pet',
            'required': True,
            'schema': PetSchema
        }
    ]
    responses = {
        200: {
            'description': 'Registered',
            'schema': fields.Str()
        }
    }

    def post(self):
        return 'registered'

app = Flask(__name__)
app.add_url_rule(
    '/random',
    view_func=RandomView.as_view('random'),
    methods=['POST']
)
Swagger(app)


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

正常なリクエストは以下の通りです
validation 機能を入れることでこのリクエストがどうなるか確認します

  • curl -v -XPOST -H 'content-type: application/json' -d '{"category":[{"id":1,"name":"rodent"}],"name":"Mickey"}' 'localhost:5000/random'

validation = True にしてみる

validation = True にするには View クラスのフィールドで有効にするだけです

class RandomView(SwaggerView):
    parameters = [
        {
            'in': 'body',
            'name': 'Pet',
            'description': 'Register a pet',
            'required': True,
            'schema': PetSchema
        }
    ]
    responses = {
        200: {
            'description': 'Registered',
            'schema': fields.Str()
        }
    }
    validation = True

この設定でエラーとなる挙動は以下の通りです

content-type ヘッダがセットされていない場合

  • リクエスト

    • curl -v -XPOST -d '{"category":[{"id":1,"name":"rodent"}],"name":"Mickey"}' 'localhost:5000/random'
  • レスポンス

    • No data to validate

required=True がない場合

  • リクエスト
    • curl -v -XPOST -H 'content-type: application/json' -d '{"category":[{"id":1,"name":"rodent"}]}' 'localhost:5000/random'
  • レスポンス
    • 'name' is a required property Failed validating 'required' in schema: で正しいスキーマ情報が表示される

こんな感じで最低限のチェックを行ってくれる感じです

レスポンス情報をカスタマイズする方法

現状はないようです
もしカスタマイズしたい場合は validation_function を指定して自分で validation 処理を実装する必要があるようです

validation_function を使用する方法

がしかし、どうやら Marshmallow Schemas で validation_function を使用する方法はないです

Marshmallow Schemas の場合すべてクラスで定義します
validation_function を使うためには swagger の定義ファイル or 定義の dictionary オブジェクトが必要になります
無理矢理使うことはできなくはないですが、せっかくクラスで定義したものをファイル or dictionary でもう一度定義しなければいけないのはかなり微妙な感じになると思います

試していないですが marshmallow の機能で Schema からサンプルデータを突っ込んで JSON なり dictionary を生成する機能があるので、それを使えばできなくはないと思います
が、それも微妙かなと思います

ではどうするのがいいか

Marshmallow schemas を使っている場合は以下のどちらかで validation するしかなさそうです

  • デフォルトの機能の validate=True を使う
  • SwaggerView 内で定義したメソッド内で独自の validation 機構を作成する、そこで Response を abort する

かなと思います
自分が調べた限りだとこの 2 つのどちらかになりそうです

最後に

Marshmallow Schemas で validation と validation_function 機能を試してみました
結論としてはデフォルトの validation を使わず自力で validation 用のメソッドを実装するのが一番良いかなと思います

情報が少ないので何とも言えませんがコードを直接見たりすれば他の解決方法が見つかるかもしれません (自分は探せませんでした、というか自力 validation を作る方が楽だと判断しました)

参考サイト

0 件のコメント:

コメントを投稿