从您的Flask项目中提取swagger规范
项目描述
Flasgger
为您的Flask API提供易于使用的Swagger UI
Flasgger是一个Flask扩展,可以从您的API中所有注册的Flask视图中提取OpenAPI规范。
Flasgger 还内置了 SwaggerUI,因此您可以访问 http://localhost:5000/apidocs 并可视化以及与您的 API 资源进行交互。
Flasgger 还提供了对传入数据的 验证,使用相同的规范,它可以验证接收到的 POST、PUT、PATCH 数据是否与使用 YAML、Python 字典 或 Marshmallow 模式 定义的方案有效。
Flasgger 可以与简单的函数视图或 MethodViews 一起工作,使用 docstring 作为规范,或者使用 @swag_from
装饰器从 YAML 或 dict 获取规范,并提供 SwaggerView,它可以使用 Marshmallow 模式 作为规范。
Flasgger 与 Flask-RESTful
兼容,因此您可以使用 Resources
和 swag
规范一起使用,请参阅 restful 示例。
Flasgger 还支持将 Marshmallow APISpec
作为规范的基础模板,如果您使用 Marshmallow 的 APISPec,请参阅 apispec 示例。
目录
- 主要贡献者
- 示例和演示应用
- 安装
- 入门指南
- 使用相同的数据验证您的 API POST 主体。
- 将定义的方案作为 Python 字典获取
- HTML 清洁器
- Swagger UI 和模板
- 支持 OpenAPI 3.0
- 使用默认数据初始化 Flasgger
- 自定义默认配置
由 gh-md-toc 创建
主要贡献者
示例和演示应用
有一些 示例应用,您还可以在 Flasgger 演示应用 中尝试示例。
注意:所有示例应用也都是测试用例,并在 Travis CI 上自动运行以确保质量和覆盖率。
Docker
示例和演示应用也可以作为 Docker 图像/容器构建和运行。
docker build -t flasgger .
docker run -it --rm -p 5000:5000 --name flasgger flasgger
然后通过 http://localhost:5000 访问 Flasgger 演示应用。
安装
在你的虚拟环境里执行以下操作:
确保你有最新的 setuptools
pip install -U setuptools
然后安装 beta 版本(推荐)
pip install flasgger==0.9.7b2
或者(为遗留应用提供的最新稳定版)
pip install flasgger==0.9.5
或者(开发版本)
pip install https://github.com/flasgger/flasgger/tarball/master
注意:如果您想使用 Marshmallow 模式,您还需要运行
pip install marshmallow apispec
如何运行测试
(您可以在 .travis.yml 的 before_install
部分看到此命令)
在你的虚拟环境里
pip install -r requirements.txt
pip install -r requirements-dev.txt
make test
入门指南
使用 docstrings 作为规范
创建一个名为例如 colors.py
的文件
from flask import Flask, jsonify
from flasgger import Swagger
app = Flask(__name__)
swagger = Swagger(app)
@app.route('/colors/<palette>/')
def colors(palette):
"""Example endpoint returning a list of colors by palette
This is using docstrings for specifications.
---
parameters:
- name: palette
in: path
type: string
enum: ['all', 'rgb', 'cmyk']
required: true
default: all
definitions:
Palette:
type: object
properties:
palette_name:
type: array
items:
$ref: '#/definitions/Color'
Color:
type: string
responses:
200:
description: A list of colors (may be filtered by palette)
schema:
$ref: '#/definitions/Palette'
examples:
rgb: ['red', 'green', 'blue']
"""
all_colors = {
'cmyk': ['cyan', 'magenta', 'yellow', 'black'],
'rgb': ['red', 'green', 'blue']
}
if palette == 'all':
result = all_colors
else:
result = {palette: all_colors.get(palette)}
return jsonify(result)
app.run(debug=True)
现在运行
python colors.py
然后访问: http://localhost:5000/apidocs/
您应该得到以下结果:
使用外部 YAML 文件
保存一个新文件 colors.yml
Example endpoint returning a list of colors by palette
In this example the specification is taken from external YAML file
---
parameters:
- name: palette
in: path
type: string
enum: ['all', 'rgb', 'cmyk']
required: true
default: all
definitions:
Palette:
type: object
properties:
palette_name:
type: array
items:
$ref: '#/definitions/Color'
Color:
type: string
responses:
200:
description: A list of colors (may be filtered by palette)
schema:
$ref: '#/definitions/Palette'
examples:
rgb: ['red', 'green', 'blue']
让我们使用相同的示例,只更改视图函数。
from flasgger import swag_from
@app.route('/colors/<palette>/')
@swag_from('colors.yml')
def colors(palette):
...
如果您不想使用装饰器,您可以使用 file:
短路方式使用 docstring。
@app.route('/colors/<palette>/')
def colors(palette):
"""
file: colors.yml
"""
...
使用字典作为原始规范
创建一个如下所示的 Python 字典:
specs_dict = {
"parameters": [
{
"name": "palette",
"in": "path",
"type": "string",
"enum": [
"all",
"rgb",
"cmyk"
],
"required": "true",
"default": "all"
}
],
"definitions": {
"Palette": {
"type": "object",
"properties": {
"palette_name": {
"type": "array",
"items": {
"$ref": "#/definitions/Color"
}
}
}
},
"Color": {
"type": "string"
}
},
"responses": {
"200": {
"description": "A list of colors (may be filtered by palette)",
"schema": {
"$ref": "#/definitions/Palette"
},
"examples": {
"rgb": [
"red",
"green",
"blue"
]
}
}
}
}
现在以相同的函数替换 YAML 文件中的字典。
@app.route('/colors/<palette>/')
@swag_from(specs_dict)
def colors(palette):
"""Example endpoint returning a list of colors by palette
In this example the specification is taken from specs_dict
"""
...
使用 Marshmallow 模式
首先:
pip install marshmallow apispec
用法 #1:
SwaggerView
from flask import Flask, jsonify
from flasgger import Swagger, SwaggerView, Schema, fields
class Color(Schema):
name = fields.Str()
class Palette(Schema):
pallete_name = fields.Str()
colors = fields.Nested(Color, many=True)
class PaletteView(SwaggerView):
parameters = [
{
"name": "palette",
"in": "path",
"type": "string",
"enum": ["all", "rgb", "cmyk"],
"required": True,
"default": "all"
}
]
responses = {
200: {
"description": "A list of colors (may be filtered by palette)",
"schema": Palette
}
}
def get(self, palette):
"""
Colors API using schema
This example is using marshmallow schemas
"""
all_colors = {
'cmyk': ['cyan', 'magenta', 'yellow', 'black'],
'rgb': ['red', 'green', 'blue']
}
if palette == 'all':
result = all_colors
else:
result = {palette: all_colors.get(palette)}
return jsonify(result)
app = Flask(__name__)
swagger = Swagger(app)
app.add_url_rule(
'/colors/<palette>',
view_func=PaletteView.as_view('colors'),
methods=['GET']
)
app.run(debug=True)
用法 #2:
来自 flasgger 的自定义模式
Body
- 支持 marshmallow 中的所有字段查询
- 支持在 Marshmallow 中使用简单字段(Int, String 等)路径
- 仅支持 int 和 str
from flask import Flask, abort
from flasgger import Swagger, Schema, fields
from marshmallow.validate import Length, OneOf
app = Flask(__name__)
Swagger(app)
swag = {"swag": True,
"tags": ["demo"],
"responses": {200: {"description": "Success request"},
400: {"description": "Validation error"}}}
class Body(Schema):
color = fields.List(fields.String(), required=True, validate=Length(max=5), example=["white", "blue", "red"])
def swag_validation_function(self, data, main_def):
self.load(data)
def swag_validation_error_handler(self, err, data, main_def):
abort(400, err)
class Query(Schema):
color = fields.String(required=True, validate=OneOf(["white", "blue", "red"]))
def swag_validation_function(self, data, main_def):
self.load(data)
def swag_validation_error_handler(self, err, data, main_def):
abort(400, err)
swag_in = "query"
@app.route("/color/<id>/<name>", methods=["POST"], **swag)
def index(body: Body, query: Query, id: int, name: str):
return {"body": body, "query": query, "id": id, "name": name}
if __name__ == "__main__":
app.run(debug=True)
注意:请查看
examples/validation.py
以获取更完整的示例。
注意:在路径规则中捕获参数时,始终使用显式类型,不好的示例:
/api/<username>
,好的示例:/api/<string:username>
使用 Flask RESTful 资源
Flasgger 与 Flask-RESTful 兼容,您只需安装 pip install flask-restful
然后即可
from flask import Flask
from flasgger import Swagger
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
swagger = Swagger(app)
class Username(Resource):
def get(self, username):
"""
This examples uses FlaskRESTful Resource
It works also with swag_from, schemas and spec_dict
---
parameters:
- in: path
name: username
type: string
required: true
responses:
200:
description: A single user item
schema:
id: User
properties:
username:
type: string
description: The name of the user
default: Steven Wilson
"""
return {'username': username}, 200
api.add_resource(Username, '/username/<username>')
app.run(debug=True)
自动解析外部 YAML 文档和 MethodView
Flasgger 可以配置为自动解析外部 YAML API 文档。在您的 app.config['SWAGGER']
中设置 doc_dir
,Swagger 将通过在 doc_dir
中查找以端点名称和方法名称存储的 YAML 文件来加载 API 文档。例如,'doc_dir': './examples/docs/'
和文件 ./examples/docs/items/get.yml
将为 ItemsView
方法的 get
提供Swagger文档。
此外,当使用如上所示的 Flask RESTful 时,通过在构建 Swagger
时传递 parse=True
,Flasgger 将使用 flask_restful.reqparse.RequestParser
,定位所有 MethodView
并将解析和验证后的数据存储在 flask.request.parsed_data
中。
处理单个函数的多个 http 方法和路由
您可以根据端点或方法来区分规范
from flasgger.utils import swag_from
@app.route('/api/<string:username>', endpoint='with_user_name', methods=['PUT', 'GET'])
@app.route('/api/', endpoint='without_user_name')
@swag_from('path/to/external_file.yml', endpoint='with_user_name')
@swag_from('path/to/external_file_no_user_get.yml', endpoint='without_user_name', methods=['GET'])
@swag_from('path/to/external_file_no_user_put.yml', endpoint='without_user_name', methods=['PUT'])
def fromfile_decorated(username=None):
if not username:
return "No user!"
return jsonify({'username': username})
您可以通过多次注册 url_rule
在 MethodView
或 SwaggerView
的多个方法中实现相同的效果。请参阅 examples/example_app
使用相同的数据验证您的 API POST 主体。
将 swag_from
的 validation 参数设置为 True
将自动验证传入数据
from flasgger import swag_from
@swag_from('defs.yml', validation=True)
def post():
# if not validate returns ValidationError response with status 400
# also returns the validation message.
使用 swagger.validate
注解也是可能的
from flasgger import Swagger
swagger = Swagger(app)
@swagger.validate('UserSchema')
def post():
'''
file: defs.yml
'''
# if not validate returns ValidationError response with status 400
# also returns the validation message.
您还可以手动调用 validate
from flasgger import swag_from, validate
@swag_from('defs.yml')
def post():
validate(request.json, 'UserSchema', 'defs.yml')
# if not validate returns ValidationError response with status 400
# also returns the validation message.
您也可以在 SwaggerView
中定义 validation=True
并使用 specs_dict
进行验证。
请参阅 examples/validation.py
获取更多信息。
所有验证选项都可以在 https://json-schema.fullstack.org.cn/latest/json-schema-validation.html 中找到
自定义验证
默认情况下,Flasgger 将使用 python-jsonschema 来执行验证。
只要它们符合要求,就支持自定义验证函数
- 接受两个,且只有两个位置参数
- 要验证的数据作为第一个;
- 作为第二个参数的验证方案
- 当验证失败时抛出任何类型的异常。
任何返回值都将被丢弃。
将函数提供给 Swagger 实例将使其成为默认值
from flasgger import Swagger
swagger = Swagger(app, validation_function=my_validation_function)
将函数作为 swag_from
或 swagger.validate
注解的参数或直接提供给 validate
函数将强制使用默认验证函数进行 Swagger
from flasgger import swag_from
@swag_from('spec.yml', validation=True, validation_function=my_function)
...
from flasgger import Swagger
swagger = Swagger(app)
@swagger.validate('Pet', validation_function=my_function)
...
from flasgger import validate
...
validate(
request.json, 'Pet', 'defs.yml', validation_function=my_function)
处理验证错误
默认情况下,Flasgger 将通过返回带有错误信息的 400 BAD REQUEST 响应来处理验证错误。
只要它符合要求,就可以提供自定义验证错误处理函数来替代默认行为
- 接受三个,且只有三个位置参数
- 作为第一个参数抛出的错误;
- 作为第二个参数的验证失败的数据;
- 作为第三个参数用于验证的方案
将函数提供给 Swagger 实例将使其成为默认值
from flasgger import Swagger
swagger = Swagger(app, validation_error_handler=my_handler)
将函数作为 swag_from
或 swagger.validate
注解的参数或直接提供给 validate
函数将强制使用默认验证函数进行 Swagger
from flasgger import swag_from
@swag_from(
'spec.yml', validation=True, validation_error_handler=my_handler)
...
from flasgger import Swagger
swagger = Swagger(app)
@swagger.validate('Pet', validation_error_handler=my_handler)
...
from flasgger import validate
...
validate(
request.json, 'Pet', 'defs.yml',
validation_error_handler=my_handler)
有关自定义验证错误处理函数的用法示例,请参阅 example validation_error_handler.py
将定义的方案作为 Python 字典获取
您可能希望使用您在 Swagger 规范中定义的方案作为字典来使用,而不需要复制规范。为此,您可以使用 get_schema
方法
from flask import Flask, jsonify
from flasgger import Swagger, swag_from
app = Flask(__name__)
swagger = Swagger(app)
@swagger.validate('Product')
def post():
"""
post endpoint
---
tags:
- products
parameters:
- name: body
in: body
required: true
schema:
id: Product
required:
- name
properties:
name:
type: string
description: The product's name.
default: "Guarana"
responses:
200:
description: The product inserted in the database
schema:
$ref: '#/definitions/Product'
"""
rv = db.insert(request.json)
return jsonify(rv)
...
product_schema = swagger.get_schema('product')
此方法返回一个字典,其中包含 Flasgger 方案 id、所有定义的参数以及必需参数列表。
HTML 清洁器
默认情况下,Flasgger 将尝试在 YAML 定义中清理内容,将每个 \n
替换为 <br>
,但您可以通过设置另一个类型的清理器来更改此行为。
from flasgger import Swagger, NO_SANITIZER
app =Flask()
swagger = Swagger(app, sanitizer=NO_SANITIZER)
您可以编写自己的清理器
swagger = Swagger(app, sanitizer=lambda text: do_anything_with(text))
还有一个 Markdown 解析器可用,如果您想在规范说明中使用 Markdown,请使用 MK_SANITIZER
Swagger UI 和模板
您可以在应用程序中覆盖 templates/flasgger/index.html
,这个模板将成为 SwaggerUI 的 index.html
。以 flasgger/ui2/templates/index.html
作为自定义的基础。
Flasgger 支持 Swagger UI 版本 2 和 3,版本 3 仍然是实验性的,但您可以通过设置 app.config['SWAGGER']['uiversion']
来尝试。
app = Flask(__name__)
app.config['SWAGGER'] = {
'title': 'My API',
'uiversion': 3
}
swagger = Swagger(app)
支持 OpenAPI 3.0
对于 OpenAPI 3.0 的实验性支持,应在使用 SwaggerUI 3 时正常工作。要使用 OpenAPI 3.0,请将 app.config['SWAGGER']['openapi']
设置为当前 SwaggerUI 3 所支持的版本,例如 '3.0.2'
。
有关使用 callbacks
和 requestBody
的示例,请参阅 callbacks 示例。
外部加载 Swagger UI 和 jQuery JS/CSS
从 Flasgger 0.9.2 版本开始,您可以为 Flasgger 默认模板中加载的 Swagger 和 jQuery 库指定外部 URL 位置。如果省略以下配置属性,Flasgger 将提供它包含的静态版本 - 这些版本可能比当前的 Swagger UI v2 或 v3 发布版本要旧。
以下示例从 unpkg.com 加载 Swagger UI 和 jQuery 版本
swagger_config = Swagger.DEFAULT_CONFIG
swagger_config['swagger_ui_bundle_js'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js'
swagger_config['swagger_ui_standalone_preset_js'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui-standalone-preset.js'
swagger_config['jquery_js'] = '//unpkg.com/jquery@2.2.4/dist/jquery.min.js'
swagger_config['swagger_ui_css'] = '//unpkg.com/swagger-ui-dist@3/swagger-ui.css'
Swagger(app, config=swagger_config)
使用默认数据初始化 Flasgger
您可以使用任何默认数据开始您的 Swagger 规范
template = {
"swagger": "2.0",
"info": {
"title": "My API",
"description": "API for my data",
"contact": {
"responsibleOrganization": "ME",
"responsibleDeveloper": "Me",
"email": "me@me.com",
"url": "www.me.com",
},
"termsOfService": "http://me.com/terms",
"version": "0.0.1"
},
"host": "mysite.com", # overrides localhost:500
"basePath": "/api", # base bash for blueprint registration
"schemes": [
"http",
"https"
],
"operationId": "getmyData"
}
swagger = Swagger(app, template=template)
然后模板是默认数据,除非某些视图更改它。您也可以提供所有规范作为模板,并且没有视图。或者视图在外部 APP 中。
在运行时获取默认数据
有时您需要在运行时根据动态值获取一些数据,例如:您想检查 request.is_secure
以决定 schemes
将是 https
。您可以通过使用 LazyString
来实现这一点。
from flask import Flask
from flasgger import, Swagger, LazyString, LazyJSONEncoder
app = Flask(__init__)
# Set the custom Encoder (Inherit it if you need to customize)
app.json_encoder = LazyJSONEncoder
template = dict(
info={
'title': LazyString(lambda: 'Lazy Title'),
'version': LazyString(lambda: '99.9.9'),
'description': LazyString(lambda: 'Hello Lazy World'),
'termsOfService': LazyString(lambda: '/there_is_no_tos')
},
host=LazyString(lambda: request.host),
schemes=[LazyString(lambda: 'https' if request.is_secure else 'http')],
foo=LazyString(lambda: "Bar")
)
Swagger(app, template=template)
LazyString
值仅在实际编码值时评估,因此您可以使用 Flask 的 request, session, g, 等
,并且也可能想访问数据库。
位于反向代理后面
有时您在反向代理(例如 NGINX)后面提供 Swagger 文档。遵循 Flask 指导 时,Swagger 文档将正确加载,但“试用”按钮指向了错误的位置。可以通过以下代码修复此问题
from flask import Flask, request
from flasgger import Swagger, LazyString, LazyJSONEncoder
app = Flask(__name__)
app.json_encoder = LazyJSONEncoder
template = dict(swaggerUiPrefix=LazyString(lambda : request.environ.get('HTTP_X_SCRIPT_NAME', '')))
swagger = Swagger(app, template=template)
自定义默认配置
可以提供自定义配置,例如不同的规范路由或禁用 Swagger UI,这些配置可以提供给 Flasgger
swagger_config = {
"headers": [
],
"specs": [
{
"endpoint": 'apispec_1',
"route": '/apispec_1.json',
"rule_filter": lambda rule: True, # all in
"model_filter": lambda tag: True, # all in
}
],
"static_url_path": "/flasgger_static",
# "static_folder": "static", # must be set by user
"swagger_ui": True,
"specs_route": "/apidocs/"
}
swagger = Swagger(app, config=swagger_config)
提取定义
当在规范中找到 id
时可以提取定义
from flask import Flask, jsonify
from flasgger import Swagger
app = Flask(__name__)
swagger = Swagger(app)
@app.route('/colors/<palette>/')
def colors(palette):
"""Example endpoint returning a list of colors by palette
---
parameters:
- name: palette
in: path
type: string
enum: ['all', 'rgb', 'cmyk']
required: true
default: all
responses:
200:
description: A list of colors (may be filtered by palette)
schema:
id: Palette
type: object
properties:
palette_name:
type: array
items:
schema:
id: Color
type: string
examples:
rgb: ['red', 'green', 'blue']
"""
all_colors = {
'cmyk': ['cyan', 'magenta', 'yellow', 'black'],
'rgb': ['red', 'green', 'blue']
}
if palette == 'all':
result = all_colors
else:
result = {palette: all_colors.get(palette)}
return jsonify(result)
app.run(debug=True)
在这个示例中,您不需要传递 definitions
,但需要将 id
添加到您的模式中。
Python2 兼容性
版本 0.9.5.*
将是最后一个支持 Python2 的版本。请将讨论引导至 #399。
项目详细信息
flasgger-0.9.7.1.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | ca098e10bfbb12f047acc6299cc70a33851943a746e550d86e65e60d4df245fb |
|
MD5 | 3f2d4b14b25b22a0e99008c6ad826ba4 |
|
BLAKE2b-256 | 8ae405e80adeadc39f171b51bd29b24a6d9838127f3aaa1b07c1501e662a8cee |