Flask Apiドキュメント管理とSwagger
この記事はブログで最初に発表されました.https://blog.ihypo.net/152551...
Flaskは自由度が高く、柔軟性が高いことで知られるPython Webフレームワークです.しかし、高い柔軟性は、コードのメンテナンスコストが無限であることを意味し、高い自由度は、コードの品質がプログラマー自身に依存し、一貫した基準と規範がないことを意味します.そのため、チーム内で開発する場合、Flaskプロジェクトはコードとドキュメント仕様を確立して、大きなばらつきがないことを保証する必要があります.
本稿では,FlaskプロジェクトのApi仕様をApiの観点から探究し,Apiドキュメントの最適姿勢を得る.ドキュメントの作成と整理には、コードの作成に劣らず大きな労力がかかることはよく知られています.そのため、時間がきつい場合、ドキュメントはまず無視される作業です.しかし、プロジェクトが初期にドキュメントが存在しても、後続の反復では、ドキュメントの遅れが深刻であり、ドキュメントがないよりも誤導が発生します.
したがって、個人的には、ドキュメントはコードに従って移動し、コードが変更されたときにドキュメントもフォローアップしなければならないと考えていますが、人間は信頼できない原則に基づいて、ドキュメントは人工的にメンテナンスするのではなく、コードによって生成されるのが理想的です.コードに変更があれば、ドキュメントも自動的に更新され、非常に優雅なことになります.多くのドキュメントでは現実的ではありませんが、Apiドキュメントでは実現コストは高くありません.
Flask-RESTPlus
REST Apiにとって、
インストール
インストール
または、
最小Demo
実行後の効果は次のとおりです.
じっこう
ここでは完全な小さなプロジェクトを実現して実践・紹介します
Model
idとusernameを含むユーザーmodel:
図書モデル、id、名前、価格を含む:
注文モデル、id、購入者id、図書id、作成時間を含む:
青写真
Flaskで大規模なWebプロジェクトを構築し、青写真でルーティンググループを作成し、青写真に共通のルール(url接頭辞、静的ファイルパス、テンプレートパスなど)を追加できます.このプロジェクトではapi青写真を1つしか使いませんが、実際にはopenapi青写真、internal api青写真を使って大きな分類を区別する可能性があります.
Api青写真:
そして、異なるnamespaceを作成して、自分のapiコードを書くことができます.一方、appファクトリにblueprintを登録するだけで、自分の作成したapiをflask appにマウントできます.
Apiの多くのツールメソッドはapiオブジェクトに依存するため、namespaceを登録するときにループ参照を避ける必要があります.また、この青写真を登録するときは、まずnamespaceを登録する必要があります.そうしないと404になります.このライブラリの多くの方法はapiオブジェクトに依存しすぎて、設計が合理的ではないと感じて、簡単に繰り返し引用して、とても優雅ではありません.
namespaceの登録:
次はApiの作成です.
Apiの作成
リストと作成
まず、ユーザーのリストとApiの作成を完了します.コードは次のとおりです.
上のコードを説明するには、まずuser modelを作成して
ここでは、パラメータチェックに参加せず、apiドキュメントにレンダリングしてapiがどのような結果を返すか、apiをどのように呼び出すべきかをマークするフィールドとフィールドの説明を定義します.
次に、現在使用されているアクセサリーを紹介します. プログラムを実行すると、次の結果が表示されます.
try itでapiを呼び出すこともできます.
クエリーと更新
ルーティングはクラスにバインドされるため、'/users/user_について、このクラスが処理できるurlが限定される.id'類似のパスは、個別のクラスで処理する必要があります.
urlの変更と新しく導入された2つの装飾器が表示されます. プログラムを実行した後、idに基づいてユーザーを取得しようとします.
注意:namespaceのnameはurlに結合されます.たとえば、上のurlの「users」はnamespace nameです.
ネストされたApi
ユーザApiと図書Apiは基本的に同じで簡単であるが,受注Apiではユーザ情報と図書情報を含める必要があり,実装上はやや異なる.
ここでは、
メモ:ここでreturnは辞書ですが、理想的にはクラス(userフィールドとbookフィールド)であるべきです.データベース操作がないため、処理を簡素化します.
ここまで、この小さなプロジェクトは書き終わったので、最後の運行効果図は以下の通りです.
改造する
この簡単なデモでわかる
上記のコードを使用すると、主に2つのことがわかります.Api層の改造 デザインApi Model Api層の改造は2点に及ぶ.urlはblueprint、api obj、namespaceの3つのものから構成されているため、どのように分配するかを設計する必要があり、apiの一部を書き換える実現もある可能性がある.しかし、理想的なapi-service-modelアーキテクチャのプログラムは、apiが比較的薄い層であるべきで、アクセスするのは難しくなく、些細なことです.
Api Modelは一般的に既存のプロジェクトにはないもので、パラメータチェックのモデル(
Swagger
Swaggerは非常にポピュラーなApiドキュメント管理、インタラクティブツールであり、チーム内のApi管理、サービスコンポーネントのドッキングに適しています.その使い勝手と重要度は言うまでもなく、以下、上述のdemoに基づいて、Swaggerドキュメントを完成させ、ドキュメントに基づいてドッキングのためのclientを生成する.
Swaggerドキュメントを取得
コンソールには、プログラムにアクセスするときに次のように表示されます.
はい、これがSwaggerドキュメントです.
コード生成
Swaggerを使用してドキュメントを生成するには
macOSでダウンロード:
ヘルプはhelp名で表示できます.
Pythonクライアントの生成:
実行が完了すると、現在のパスの
まとめ
本稿では
個人公衆番号へようこそ:CS実験室
Flaskは自由度が高く、柔軟性が高いことで知られるPython Webフレームワークです.しかし、高い柔軟性は、コードのメンテナンスコストが無限であることを意味し、高い自由度は、コードの品質がプログラマー自身に依存し、一貫した基準と規範がないことを意味します.そのため、チーム内で開発する場合、Flaskプロジェクトはコードとドキュメント仕様を確立して、大きなばらつきがないことを保証する必要があります.
本稿では,FlaskプロジェクトのApi仕様をApiの観点から探究し,Apiドキュメントの最適姿勢を得る.ドキュメントの作成と整理には、コードの作成に劣らず大きな労力がかかることはよく知られています.そのため、時間がきつい場合、ドキュメントはまず無視される作業です.しかし、プロジェクトが初期にドキュメントが存在しても、後続の反復では、ドキュメントの遅れが深刻であり、ドキュメントがないよりも誤導が発生します.
したがって、個人的には、ドキュメントはコードに従って移動し、コードが変更されたときにドキュメントもフォローアップしなければならないと考えていますが、人間は信頼できない原則に基づいて、ドキュメントは人工的にメンテナンスするのではなく、コードによって生成されるのが理想的です.コードに変更があれば、ドキュメントも自動的に更新され、非常に優雅なことになります.多くのドキュメントでは現実的ではありませんが、Apiドキュメントでは実現コストは高くありません.
Flask-RESTPlus
REST Apiにとって、
Flask-RESTPlus
優れたApiドキュメント生成ツールであり、このパッケージはFlaskルーティング層の作成方式を置き換え、自分の文法でApiの詳細を規定し、Apiドキュメントを生成する.インストール
インストール
Flask-RESTPlus
:pip install flask-restplus
または、
easy_install flask-restplus
最小Demo
Flask-RESTPlus
を使用する場合は、requestのパラメータ解析やresponseの戻りフォーマットなど、このライブラリで規定された方法でApiレイヤを記述する必要があります.hello worldレベルのモデル:from flask import Flask
from flask_restplus import Resource, Api
app = Flask(__name__)
api = Api(app, prefix="/v1", title="Users", description="Users CURD api.")
@api.route('/users')
class UserApi(Resource):
def get(self):
return {'user': '1'}
if __name__ == '__main__':
app.run()
実行後の効果は次のとおりです.
じっこう
ここでは完全な小さなプロジェクトを実現して実践・紹介します
Flask-RESTPlus
このライブラリ.私たちは簡単な図書注文システムを実現し、ユーザー、図書、注文のCURDを実現します.Model
idとusernameを含むユーザーmodel:
class User(object):
user_id = None
username = None
def __init__(self, username: str):
self.user_id = str(uuid.uuid4())
self.username = username
図書モデル、id、名前、価格を含む:
class Book(object):
book_id = None
book_name = None
price = None
def __init__(self, book_name: str, book_price: float):
self.book_id = str(uuid.uuid4())
self.book_name = book_name
self.price = book_price
注文モデル、id、購入者id、図書id、作成時間を含む:
class Order(object):
order_id = None
user_id = None
book_id = None
created_at = None
def __init__(self, user_id, book_id):
self.order_id = str(uuid.uuid4())
self.user_id = user_id
self.book_id = book_id
self.created_at = int(time.time())
青写真
Flaskで大規模なWebプロジェクトを構築し、青写真でルーティンググループを作成し、青写真に共通のルール(url接頭辞、静的ファイルパス、テンプレートパスなど)を追加できます.このプロジェクトではapi青写真を1つしか使いませんが、実際にはopenapi青写真、internal api青写真を使って大きな分類を区別する可能性があります.
Flask-RESTPlus
のclass::Api
そのまま青写真の下に掛けておくと、Flaskの青写真を利用して機能モジュールを分類したり、Api
のバージョンを利用してApiバージョンを管理したり、小さなモジュール分類についてはApi
のnamespaceを利用することができます.ここではuser namespace
に分けることができます.book namespace
和order namespace
:Api青写真:
from flask import Blueprint
from flask_restplus import Api
api_blueprint = Blueprint("open_api", __name__, url_prefix="/api")
api = Api(api_blueprint, version="1.0",
prefix="/v1", title="OpenApi", description="The Open Api Service")
そして、異なるnamespaceを作成して、自分のapiコードを書くことができます.一方、appファクトリにblueprintを登録するだけで、自分の作成したapiをflask appにマウントできます.
def create_app():
app = Flask("Flask-Web-Demo")
# register api namespace
register_api()
# register blueprint
from apis import api_blueprint
app.register_blueprint(api_blueprint)
return app
Apiの多くのツールメソッドはapiオブジェクトに依存するため、namespaceを登録するときにループ参照を避ける必要があります.また、この青写真を登録するときは、まずnamespaceを登録する必要があります.そうしないと404になります.このライブラリの多くの方法はapiオブジェクトに依存しすぎて、設計が合理的ではないと感じて、簡単に繰り返し引用して、とても優雅ではありません.
namespaceの登録:
def register_api():
from apis.user_api import ns as user_api
from apis.book_api import ns as book_api
from apis.order_api import ns as order_api
from apis import api
api.add_namespace(user_api)
api.add_namespace(book_api)
api.add_namespace(order_api)
次はApiの作成です.
Apiの作成
リストと作成
まず、ユーザーのリストとApiの作成を完了します.コードは次のとおりです.
from flask_restplus import Resource, fields, Namespace
from model import User
from apis import api
ns = Namespace("users", description="Users CURD api.")
user_model = ns.model('UserModel', {
'user_id': fields.String(readOnly=True, description='The user unique identifier'),
'username': fields.String(required=True, description='The user nickname'),
})
user_list_model = ns.model('UserListModel', {
'users': fields.List(fields.Nested(user_model)),
'total': fields.Integer,
})
@ns.route("")
class UserListApi(Resource):
#
users = [User("HanMeiMei"), User("LiLei")]
@ns.doc('get_user_list')
@ns.marshal_with(user_list_model)
def get(self):
return {
"users": self.users,
"total": len(self.users),
}
@ns.doc('create_user')
@ns.expect(user_model)
@ns.marshal_with(user_model, code=201)
def post(self):
user = User(api.payload['username'])
return user
上のコードを説明するには、まずuser modelを作成して
Flask-RESTPlus
jsonのレンダリングと解析方法を知る必要があります.user_model = ns.model('UserModel', {
'user_id': fields.String(readOnly=True, description='The user unique identifier'),
'username': fields.String(required=True, description='The user nickname'),
})
ここでは、パラメータチェックに参加せず、apiドキュメントにレンダリングしてapiがどのような結果を返すか、apiをどのように呼び出すべきかをマークするフィールドとフィールドの説明を定義します.
次に、現在使用されているアクセサリーを紹介します.
@ns.doc
このapiの役割を表記する@ns.marshal_with
戻ってきたjsonのレンダリング方法をマークする@ns.expect
私たちが予想していたrequestをマークtry itでapiを呼び出すこともできます.
クエリーと更新
ルーティングはクラスにバインドされるため、'/users/user_について、このクラスが処理できるurlが限定される.id'類似のパスは、個別のクラスで処理する必要があります.
@ns.route("/")
@ns.response(404, 'User not found')
@ns.param('user_id', 'The user identifier')
class UserInfoApi(Resource):
users = [User("HanMeiMei"), User("LiLei")]
print([u.user_id for u in users])
@ns.doc("get_user_by_id")
@ns.marshal_with(user_model)
def get(self, user_id):
for u in self.users:
if u.user_id == user_id:
return u
ns.abort(404, "User {} doesn't exist".format(user_id))
@ns.doc("update_user_info")
@ns.expect(user_model)
@ns.marshal_with(user_model)
def put(self, user_id):
user = None
for u in self.users:
if u.user_id == user_id:
user = u
if not user:
ns.abort(404, "User {} doesn't exist".format(user_id))
user.username = api.payload['username']
return user
urlの変更と新しく導入された2つの装飾器が表示されます.
@ns.response
表示可能なResponse Status Codeをマークしてドキュメントにレンダリングする@ns.param
URLパラメータのタグ付け用注意:namespaceのnameはurlに結合されます.たとえば、上のurlの「users」はnamespace nameです.
ネストされたApi
ユーザApiと図書Apiは基本的に同じで簡単であるが,受注Apiではユーザ情報と図書情報を含める必要があり,実装上はやや異なる.
from flask_restplus import Resource, fields, Namespace
from model import Order, Book, User
from apis.user_api import user_model
from apis.book_api import book_model
ns = Namespace("order", description="Order CURD api.")
order_model = ns.model('OrderModel', {
"order_id": fields.String(readOnly=True, description='The order unique identifier'),
"user": fields.Nested(user_model, description='The order creator info'),
"book": fields.Nested(book_model, description='The book info.'),
"created_at": fields.Integer(readOnly=True, description='create time: unix timestamp.'),
})
order_list = ns.model('OrderListModel', {
"orders": fields.List(fields.Nested(order_model)),
"total": fields.Integer(description='len of orders')
})
book = Book("Book1", 10.5)
user = User("LiLei")
order = Order(user.user_id, book.book_id)
@ns.route("")
class UserListApi(Resource):
@ns.doc('get_order_list')
@ns.marshal_with(order_list)
def get(self):
return {
"orders": [{
"order_id": order.order_id,
"created_at": order.created_at,
"user": {
"user_id": user.user_id,
"username": user.username,
},
"book": {
"book_id": book.book_id,
"book_name": book.book_name,
"price": book.price,
}
}],
"total": 1}
@ns.doc('create_order')
@ns.expect(order_model)
@ns.marshal_with(order_model, code=201)
def post(self):
return {
"order_id": order.order_id,
"created_at": order.created_at,
"user": {
"user_id": user.user_id,
"username": user.username,
},
"book": {
"book_id": book.book_id,
"book_name": book.book_name,
"price": book.price,
}
}
ここでは、
fields.Nested
他のモデルを導入できるなど、より柔軟なフォーマットの組み合わせを使用しています.モデルは互いに参照できるので、これらのモデルを一緒に置いて、循環参照を避ける必要があります.しかし,Response解析は比較的自由であることも分かる.メモ:ここでreturnは辞書ですが、理想的にはクラス(userフィールドとbookフィールド)であるべきです.データベース操作がないため、処理を簡素化します.
ここまで、この小さなプロジェクトは書き終わったので、最後の運行効果図は以下の通りです.
改造する
この簡単なデモでわかる
Flask-RESTPlus
の使用ですが、現在はゼロから1までの完成した項目を書いているだけなので、とても使いやすいように見えますが、古い項目の改造であれば、私たちは何をする必要がありますか?上記のコードを使用すると、主に2つのことがわかります.
Api Modelは一般的に既存のプロジェクトにはないもので、パラメータチェックのモデル(
Flask-RESTPlus
Request Parsingが提供されているが、本論文では議論されていないが、ドキュメント:Request Parsing)とResponseを解析するモデルを参照することができる.これらはapiとフィールドをすべて整理する必要があり、作業量は小さくない.データベース・モデルの設計が合理的であれば、一部の作業量を軽減できるかもしれません.Swagger
Swaggerは非常にポピュラーなApiドキュメント管理、インタラクティブツールであり、チーム内のApi管理、サービスコンポーネントのドッキングに適しています.その使い勝手と重要度は言うまでもなく、以下、上述のdemoに基づいて、Swaggerドキュメントを完成させ、ドキュメントに基づいてドッキングのためのclientを生成する.
Swaggerドキュメントを取得
Flask-RESTPlus
すでにSwagger UIが統合されており、実行時に得られるインタフェースはSwagger UIによってレンダリングされる.現在必要なのは、Swaggerドキュメントjsonまたはyamlファイルを取得することです.コンソールには、プログラムにアクセスするときに次のように表示されます.
はい、これがSwaggerドキュメントです.
コード生成
Swaggerを使用してドキュメントを生成するには
macOSでダウンロード:
brew install swagger-codegen
ヘルプはhelp名で表示できます.
Hypo-MBP:~ hypo$ swagger-codegen help
usage: swagger-codegen-cli []
The most commonly used swagger-codegen-cli commands are:
config-help Config help for chosen lang
generate Generate code with chosen lang
help Display help information
langs Shows available langs
meta MetaGenerator. Generator for creating a new template set and configuration for Codegen. The output will be based on the language you specify, and includes default templates to include.
validate Validate specification
version Show version information
See 'swagger-codegen-cli help ' for more information on a specific
command.
Pythonクライアントの生成:
swagger-codegen generate -i http://127.0.0.1:5000/api/swagger.json -l python
実行が完了すると、現在のパスの
swagger_client
でapi clientを見つけることができます.まとめ
本稿では
Flask-RESTPlus
の使用を紹介したが,それ自体がSwagger構文をサポートしSwagger UIを内蔵しているため,Swaggerドッキングは単純で異常である.従って,modelを含むapi層の記述に主な作業量を置き,apiにおいて説明の役割を果たす装飾器を含む.コードには不要なコード(説明用の説明など)を多く記述する必要がありますが、これらの追加コードはコードと一致するドキュメントを生成することを支援し、コンポーネントのドッキングとメンテナンスではコストを削減します.個人公衆番号へようこそ:CS実験室