Skip to main content

LCDP Connexion - 使用 OpenAPI/Swagger 和 Flask 的 API 第一个应用程序

项目描述

连接

在 https://gitter.im/zalando/connexion 加入聊天 构建状态 工作服状态 最新版本 发展状况 Python 版本 执照

Connexion 是一个框架,可根据您的以YAML 格式描述的 API 的OpenAPI 规范 (以前称为 Swagger 规范)自动处理 HTTP 请求。Connexion 允许您编写 OpenAPI 规范,然后将端点映射到您的 Python 函数;这使它独一无二,因为许多工具会根据您的 Python 代码生成规范。您可以根据需要尽可能详细地描述您的 REST API;然后 Connexion 保证它将按照您的指定工作。

我们以这种方式构建 Connexion 是为了:

  • 简化开发过程

  • 确认对您的 API 外观的期望

连接特点:

  • 根据您的规范自动验证请求和端点参数

  • 提供 Web Swagger 控制台 UI,以便 API 的用户可以拥有实时文档,甚至可以通过它调用 API 的端点

  • 处理基于 OAuth 2 令牌的身份验证

  • 支持 API 版本控制

  • 支持负载的自动序列化。如果您的规范定义端点返回 JSON,Connexion 将自动为您序列化返回值并在 HTTP 标头中设置正确的内容类型。

为什么连接

使用 Connexion,您首先编写规范。Connexion 然后调用您的 Python 代码,处理从规范到代码的映射。这激励您编写规范,以便您的所有开发人员都可以理解您的 API 的功能,甚至在您编写一行代码之前。

如果多个团队依赖于您的 API,您可以使用 Connexion 轻松向他们发送您的 API 文档。这保证了您的 API 将遵循您编写的规范。这与Hug等框架提供的过程不同,后者会在您编写代码生成规范。基于代码生成规范的一些缺点是它们通常最终缺乏细节或将您的文档与应用程序的代码逻辑混合在一起。

其他来源/提及

Connexion 2.0 中的新功能:

  • App 和 Api 选项必须通过“options”参数提供(old_style_options已被删除)。

  • 您必须在“consumes”中指定表单内容类型才能使用表单数据。

  • Operation接口已在AbstractOperation中形式化。

  • Operation类已重命名为Swagger2Operation

  • 数组参数反序列化现在更紧密地遵循 Swagger 2.0 规范。在多次传递查询参数且 collectionFormat 为 csv 或管道的情况下,将使用最右边的值。例如,?q=1,2,3&q=4,5,6将导致q = [4, 5, 6]通过将 collectionFormat 设置为multi或导入decorators.uri_parsing.AlwaysMultiURIParser并将parser_class=AlwaysMultiURIParser传递给您的 Api ,可以使用旧行为。

  • 规范验证器库已从swagger-spec-validator更改为openapi-spec-validator

  • 以前引发SwaggerValidationError的错误现在引发InvalidSpecification异常。所有规范验证错误都应该用InvalidSpecification包装。

  • 对 nullable/x-nullable、readOnly 和 writeOnly/x-writeOnly 的支持已添加到标准 json 模式验证器中。

  • 现在可以在 api 级别(而不是应用级别)指定自定义验证器。

  • 添加了对基本身份验证和 apikey 身份验证的支持

  • 如果定义了不受支持的安全要求或缺少x-tokenInfoFunc / x-tokenInfoUrl,connexion 现在会拒绝请求,而不是允许未经安全检查的访问。

  • 不再支持访问connexion.request.user / flask.request.user ,请改用connexion.context['user']

如何使用

先决条件

Python 3.6+

安装它

在命令行中,键入:

$ pip install connexion

运行它

将您的 API YAML 放在应用程序根路径中的文件夹中(例如swagger/)。然后运行:

import connexion

app = connexion.App(__name__, specification_dir='swagger/')
app.add_api('my_api.yaml')
app.run(port=8080)

有关示例规范,请参阅Connexion Pet Store 示例应用程序。

现在您可以运行和使用 Connexion!

OAuth 2 身份验证和授权

Connexion 支持三种 OAuth 2 处理方法之一。(请参阅下面的“TODO”。)对于 Connexion,API 安全定义必须 包含“x-tokenInfoUrl”或“x-tokenInfoFunc”(或分别设置TOKENINFO_URLTOKENINFO_FUNC 环境变量)。“x-tokenInfoUrl”必须包含用于验证和获取令牌信息的 URL, “x-tokenInfoFunc”必须包含对用于获取令牌信息的函数的引用。当“x-tokenInfoUrl”和“x-tokenInfoFunc”都使用时,Connexion 将优先使用函数方法。Connexion 期望以RFC 6750中描述的格式在Authorization标头字段中接收 OAuth 令牌第 2.1 节。这方面代表了与通常的 OAuth 流程的显着差异。

动态呈现您的规范

Connexion 使用Jinja2允许通过arguments参数进行规范参数化。您可以全局(通过connexion.App构造函数)或为每个特定 API(通过connexion.App#add_api方法)定义应用程序的规范参数:

app = connexion.App(__name__, specification_dir='swagger/',
                    arguments={'global': 'global_value'})
app.add_api('my_api.yaml', arguments={'api_local': 'local_value'})
app.run(port=8080)

如果在全局和 API 上都提供了值,则 API 值将优先。

端点路由到您的 Python 视图

Connexion 使用来自每个操作对象的operationId来识别哪个 Python 函数应该处理每个 URL。

显式路由

paths:
  /hello_world:
    post:
      operationId: myapp.api.hello_world

如果您在对 http://MYHOST/hello_world的规范 POST 请求中提供此路径,它将由 myapp.api模块中的函数hello_world处理。或者,您可以在操作定义中包含 x-swagger-router-controller(或x-openapi-router-controller),使operationId相对:

paths:
  /hello_world:
    post:
      x-swagger-router-controller: myapp.api
      operationId: hello_world

请记住,Connexion 遵循HTTP 方法在 Flask 中的工作方式,因此 HEAD 请求将由规范中 GET 下指定的operationId处理。如果两种方法都支持,则可以使用connexion.request.method来确定发出了哪个请求。

自动路由

要自定义此行为,Connexion 可以使用替代 解析器——例如,RestyResolverRestyResolver将根据您规范中端点的路径和 HTTP 方法 组成一个operationId :

from connexion.resolver import RestyResolver

app = connexion.App(__name__)
app.add_api('swagger.yaml', resolver=RestyResolver('api'))
paths:
  /:
    get:
       # Implied operationId: api.get
  /foo:
    get:
       # Implied operationId: api.foo.search
    post:
       # Implied operationId: api.foo.post

  <s>'/foo/{id}'</s>:
    get:
       # Implied operationId: api.foo.get
    put:
       # Implied operationId: api.foo.put
    copy:
       # Implied operationId: api.foo.copy
    delete:
       # Implied operationId: api.foo.delete

RestyResolver将优先处理规范中遇到的任何operationId 。它还将尊重 x-router-controller。您可以导入和扩展connexion.resolver.Resolver以实现您自己的operationId (和函数)解析算法。

自动参数处理

Connexion 自动将端点规范中定义的参数映射到 Python 视图的参数作为命名参数,并尽可能使用值转换。只需使用与视图参数相同的名称定义端点参数即可。

例如,假设您有一个端点指定为:

paths:
  /foo:
    get:
      operationId: api.foo_get
      parameters:
        - name: message
          description: Some message.
          in: query
          type: string
          required: true

和视图功能:

# api.py file

def foo_get(message):
    # do something
    return 'You send the message: {}'.format(message), 200

在此示例中,Connexion 自动识别您的视图函数需要一个名为message的参数,并将端点参数message的值分配给您的视图函数。

类型铸造

只要有可能,Connexion 将尝试解析您的参数值并将类型转换为相关的 Python 本机值。当前可用的类型铸件是:

OpenAPI 类型

蟒蛇类型

整数

整数

细绳

字符串

数字

漂浮

布尔值

布尔

大批

列表

无效的

没有任何

目的

听写

如果在 Swagger 定义中使用数组类型,可以定义 collectionFormat使其不被识别。Connexion 目前支持收集格式“pipes”和“csv”。默认格式为“csv”。

Connexion 对于如何解析 URI 以获取数组类型持固执己见。多次定义的查询参数的默认行为是使用最右边的值。例如,如果您提供带有查询字符串?letters=a,b,c&letters=d,e,f的 URI,则connexion 将设置 letters = ['d', 'e', 'f']

您可以通过在应用程序或 api 选项中指定 URI 解析器来覆盖此行为。

from connexion.decorators.uri_parsing import AlwaysMultiURIParser
options = {'uri_parser_class': AlwaysMultiURIParser}
app = connexion.App(__name__, specification_dir='swagger/', options=options)

您可以通过从connexion.decorators.uri_parsing.AbstractURIParser继承来实现自己的 URI 解析行为 。

连接中包含一些 URI 解析器。

OpenAPIURIParser 默认:OpenAPI 3.0

此解析器遵循 OpenAPI 3.xx 规范,并使用style 参数。查询参数是从左到右解析的,所以如果一个查询参数定义了两次,那么最右边的定义将优先。例如,如果您提供了一个带有查询字符串 ?letters=a,b,c&letters=d,e,fstyle: simple的 URI ,那么 connexion 将设置letters = ['d', 'e', 'f' ] . 有关其他信息,请参阅 OpenAPI 3.0 样式值

Swagger2URIParser 默认:OpenAPI 2.0

此解析器遵循 Swagger 2.0 规范,并且仅当collectionFormat 设置为multi时才会将同一查询参数的多个实例连接在一起。查询参数是从左到右解析的,所以如果一个查询参数被定义了两次,那么最右边的定义获胜。例如,如果您提供了一个带有查询字符串 ?letters=a,b,c&letters=d,e,fcollectionFormat: csv的 URI ,那么 connexion 将设置letters = ['d', 'e', 'f' ]

FirstValueURIParser

此解析器的行为类似于 Swagger2URIParser,只是它更喜欢第一个定义的值。例如,如果您提供的 URI 带有查询字符串?letters=a,b,c&letters=d,e,fcollectionFormat: csv hen connexion 将设置letters = ['a', 'b', 'c']

AlwaysMultiURIParser

此解析器向后兼容 Connexion 1.x。它将同一查询参数的多个实例连接在一起。

参数验证

Connexion 可以对查询和表单数据参数应用严格的参数验证。启用此功能后,包含未在 swagger 规范中定义的参数的请求会返回 400 错误。您可以在将 API 添加到应用程序时启用它:

app.add_api('my_apy.yaml', strict_validation=True)

API 版本控制和 basePath

设置基本路径对于版本化 API 很有用。基本路径的一个示例是http ://MYHOST/1.0/hello_world中的1.0

如果您使用的是 OpenAPI 3.xx,则在规范的服务器块中设置您的基本 URL 路径。您可以指定一个完整的 URL,也可以只指定一个相对路径。

servers:
  - url: https://MYHOST/1.0
    description: full url example
  - url: /1.0
    description: relative path example

paths:
  ...

如果您使用的是 OpenAPI 2.0,您可以在 OpenAPI 2.0 规范的顶层定义一个basePath 。

basePath: /1.0

paths:
  ...

如果您不想在规范中包含基本路径,可以在将 API 添加到应用程序时提供它:

app.add_api('my_api.yaml', base_path='/1.0')

大摇大摆的 JSON

Connexion 使 JSON 格式的 OpenAPI/Swagger 规范可从API 基本路径的swagger.json(对于 OpenAPI 2.0)或 openapi.json(对于 OpenAPI 3.xx)获得。例如,如果您的基本路径是1.0,那么您的规范将在/1.0/openapi.json可用。

您可以在应用程序级别禁用提供规范 JSON:

options = {"serve_spec": False}
app = connexion.App(__name__, specification_dir='openapi/',
                    options=options)
app.add_api('my_api.yaml')

您还可以在 API 级别禁用它:

options = {"serve_spec": False}
app = connexion.App(__name__, specification_dir='openapi/')
app.add_api('my_api.yaml', options=options)

HTTPS 支持

在 API YAML 文件中指定 HTTPS 作为方案时,所服务的 Swagger UI 中的所有 URI 都是 HTTPS 端点。问题:运行的默认服务器是“普通”HTTP 服务器。这意味着 Swagger UI 不能用来玩 API。使用 Connexion 时启动 HTTPS 服务器的正确方法是什么?

Flask 描述的一种方法如下所示:

from OpenSSL import SSL
context = SSL.Context(SSL.SSLv23_METHOD)
context.use_privatekey_file('yourserver.key')
context.use_certificate_file('yourserver.crt')

app.run(host='127.0.0.1', port='12344',
        debug=False/True, ssl_context=context)

但是,Connexion 不提供 ssl_context 参数。这是因为 Flask 也没有,但它使用**kwargs将参数发送到底层werkzeug服务器。

Swagger UI 控制台

API 的 Swagger UI 可通过 pip extras 获得。您可以使用pip install connexion[swagger-ui]安装它。它将在{base_path}/ui/提供,其中base_path是 API 的基本路径。

您可以在应用程序级别禁用 Swagger UI:

app = connexion.App(__name__, specification_dir='openapi/',
                    options={"swagger_ui": False})
app.add_api('my_api.yaml')

您还可以在 API 级别禁用它:

app = connexion.App(__name__, specification_dir='openapi/')
app.add_api('my_api.yaml', options={"swagger_ui": False})

如有必要,您可以使用 swagger-ui 显式指定目录的路径,以不使用 connexion[swagger-ui] 发行版。为此,您应该指定以下选项:

options = {'swagger_path': '/path/to/swagger_ui/'}
app = connexion.App(__name__, specification_dir='openapi/', options=options)

如果您希望提供自己的 swagger-ui 发行版,请注意 connexion 需要一个名为swagger_ui/index.j2的 jinja2 文件,以便默认加载正确的swagger.json。您的index.j2文件可以 为此目的使用openapi_spec_url jinja 变量:

const ui = SwaggerUIBundle({ url: "{{ openapi_spec_url }}"})

另外,如果你想使用 swagger-ui-3.xx,它也可以通过安装 connexion[swagger-ui] 来提供,并且可以这样启用:

from swagger_ui_bundle import swagger_ui_3_path
options = {'swagger_path': swagger_ui_3_path}
app = connexion.App(__name__, specification_dir='swagger/', options=options)

服务器后端

默认情况下,Connexion 使用Flask服务器。对于异步应用程序,您还可以使用Tornado作为 HTTP 服务器。为此,请将您的服务器设置为tornado

import connexion

app = connexion.App(__name__, specification_dir='swagger/')
app.run(server='tornado', port=8080)

您可以将 Flask WSGI 应用程序与任何 WSGI 容器一起使用,例如将 Flask 与 uWSGI 一起使用(这很常见):

app = connexion.App(__name__, specification_dir='swagger/')
application = app.app # expose global WSGI application object

您也可以使用aiohttp框架作为服务器后端:

import connexion

app = connexion.AioHttpApp(__name__, specification_dir='swagger/')
app.run(port=8080)

设置并运行安装代码:

$ sudo pip3 install uwsgi
$ uwsgi --http :8080 -w app -p 16  # use 16 worker processes

有关更多信息,请参阅uWSGI 文档

文档

更多信息可在Connexion 的文档页面上找到。

变化

完整的变更日志保存在GitHub 发布页面上

为 Connexion/TODO 做贡献

我们欢迎您的想法、问题和请求请求。只需遵循通常/标准的 GitHub 实践即可。

您可以通过查看我们的ARCHITECTURE.rst了解更多关于 Connexion 的工作原理以及应用更改的位置。

除非您事先明确声明,否则您有意提交给此存储库管理员(Zalando SE,柏林)以包含在此项目中的任何重要贡献均应遵守下面编写的 Apache 许可证 2.0 的条款和条件,无需任何额外的版权信息、条款或条件。

待办事项

如果您想成为 Connexion 的更一致的贡献者,我们希望您能帮助我们解决这些问题,我们有一个我们正在寻找贡献的问题列表。

谢谢

我们要感谢 Connexion 的所有贡献者参与这个项目,并感谢 Swagger/OpenAPI 的支持。

执照

版权所有 2015 Zalando SE

根据 Apache 许可证 2.0 版(“许可证”)获得许可;除非遵守许可,否则您不得使用此文件。您可以从http://www.apache.org/licenses/LICENSE-2.0获得一份许可证副本。

除非适用法律要求或书面同意,否则根据许可分发的软件将按“原样”分发,没有任何明示或暗示的保证或条件。有关许可下的特定语言管理权限和限制,请参阅许可。

项目详情


下载文件

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

源分布

lcdp-connexion-2.9.4.tar.gz (72.8 kB 查看哈希

已上传 source

内置分布

lcdp_connexion-2.9.4-py2.py3-none-any.whl (84.9 kB 查看哈希

已上传 py2 py3