跳转到主要内容

从您的Flask项目中提取swagger规范

项目描述

Flasgger

为您的Flask API提供易于使用的Swagger UI

Build Status Code Health Coverage Status PyPI Donate with Paypal

flasgger

Flasgger是一个Flask扩展,可以从您的API中所有注册的Flask视图中提取OpenAPI规范

Flasgger 还内置了 SwaggerUI,因此您可以访问 http://localhost:5000/apidocs 并可视化以及与您的 API 资源进行交互。

Flasgger 还提供了对传入数据的 验证,使用相同的规范,它可以验证接收到的 POST、PUT、PATCH 数据是否与使用 YAMLPython 字典Marshmallow 模式 定义的方案有效。

Flasgger 可以与简单的函数视图或 MethodViews 一起工作,使用 docstring 作为规范,或者使用 @swag_from 装饰器从 YAMLdict 获取规范,并提供 SwaggerView,它可以使用 Marshmallow 模式 作为规范。

Flasgger 与 Flask-RESTful 兼容,因此您可以使用 Resourcesswag 规范一起使用,请参阅 restful 示例。

Flasgger 还支持将 Marshmallow APISpec 作为规范的基础模板,如果您使用 Marshmallow 的 APISPec,请参阅 apispec 示例。

目录

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.ymlbefore_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/

您应该得到以下结果:

colors

使用外部 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_ruleMethodViewSwaggerView 的多个方法中实现相同的效果。请参阅 examples/example_app

使用相同的数据验证您的 API POST 主体。

swag_fromvalidation 参数设置为 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_fromswagger.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_fromswagger.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'

有关使用 callbacksrequestBody 的示例,请参阅 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

项目详细信息


发布历史 发布通知 | RSS 源

下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源分布

flasgger-0.9.7.1.tar.gz (4.0 MB 查看哈希值)

由以下支持