在flask中支持多个API版本

Kee*_*per 45 python flask

我开始使用Flask和Python设计RESTful Web服务,我想知道如何在同一个项目中支持多个API版本.我正在考虑将请求的API版本放在URL中,如下所示:

/myapp/v1/Users
Run Code Online (Sandbox Code Playgroud)

一段时间后,我想在API的1.1版中添加另一个端点,并保留v1中没有改变的所有内容:

/myapp/v1.1/Users   <= Same as in v1
/myapp/v1.1/Books
Run Code Online (Sandbox Code Playgroud)

在v2中,"Users"-endpoint被更改:

/myapp/v2/Users   <= Changed in v2
/myapp/v2/Books   <= Same as in v1.1
Run Code Online (Sandbox Code Playgroud)

等等...

看看这个问题,最简单的方法可能是这样的:

@app.route('/<version>/users')
def users(version):
    # do something
    return jsonify(response)
Run Code Online (Sandbox Code Playgroud)

但我可以想象,每个新的API版本都会越难维护.因此,我想知道是否有更好的(=更容易维护和更好的结构化)方法来实现这个与Flask?

Mig*_*uel 77

我是您引用的问题的接受答案的作者.我认为这种/<version>/users方法并不像你说的那样有效.如果你必须管理三个或四个不同的版本,你最终会得到意大利面条代码.

我在那里提出的nginx想法更好,但缺点是你必须托管两个独立的应用程序.那时我错过了提到第三种选择,即为每个API版本使用蓝图.例如,考虑以下应用程序结构(为清晰起见,大大简化):

my_project
+-- api/
    +-- v1/
        +-- __init__.py
        +-- routes.py
    +-- v1_1/
        +-- __init__.py
        +-- routes.py
    +-- v2/
        +-- __init__.py
        +-- routes.py
    +-- __init__.py
    +-- common.py
Run Code Online (Sandbox Code Playgroud)

在这里,您可以api/common.py实现API的所有版本所需的常用功能.例如,您可以使用辅助功能(未装饰为路线)来响应您/users在v1和v1.1中相同的路线.

routes.py每个API版本定义的路由,并在必要时调用放入common.py功能,以避免重复的逻辑.例如,您的v1和v1.1 routes.py可以具有:

from api import common

@api.route('/users')
def get_users():
    return common.get_users()
Run Code Online (Sandbox Code Playgroud)

请注意api.route.这api是一个蓝图.将每个API版本实现为蓝图有助于将所有内容与正确的版本化URL相结合.以下是将API蓝图导入应用程序实例的示例应用程序设置代码:

from api.v1 import api as api_v1
from api.v1_1 import api as api_v1_1
from api.v2 import api as api_v2

app.register_blueprint(api_v1, url_prefix='/v1')
app.register_blueprint(api_v1_1, url_prefix='/v1.1')
app.register_blueprint(api_v2, url_prefix='/v2')
Run Code Online (Sandbox Code Playgroud)

这种结构非常好,因为它将所有API版本分开,但它们由同一个应用程序提供服务.另外一个好处是,当需要停止支持v1时,您只需删除该register_blueprint版本的调用,v1从源代码中删除该软件包即可完成.

现在,所有这些都说明了,你应该真正努力设计你的API,以最大限度地降低不得不修改版本的风险.考虑添加新路由不需要新的API版本,使用新路由扩展API非常好.现有路线的变化有时可以设计为不影响旧客户的方式.有时候,修改API并减少更多自由,但理想情况下这种情况不会经常发生.

  • @米格尔谢谢。如果你不介意的话我问几个问题。我的理解正确吗?假设我有一个 API 的初始版本 (v1)。那我想要v2。我复制整个 v1 目录并将其命名为 v2。然后,我可以在 v2 目录的 __init__.py 中设置一个蓝图,并将其注册到主应用程序中,如您最初的答案中所述。我想我担心的是我们最终仍然会得到多个版本的代码。如果一组端点没有从 v1 更改为 v2,那么该代码将在两个地方重复吗?修复需要应用于所有版本。蓝图有什么好处?结构? (2认同)
  • @thecountofzero首先,你应该尽可能避免使用多个版本.当您对API进行全面或近乎完整的改造时,这应该是最后一项措施.对于较小的更改,请设计您的API,以便它可以发展.但是,如果您需要在多个API版本上公开某些端点,那么从共享模块或包中导入这些端点绝对没有问题. (2认同)
  • @thecountofzero我看到你的场景有一些问题.如果您需要不同的响应格式,只需使用不同的内容类型(可能是vnd类型),则无需更新版本号.添加您不希望v1客户端看到的端点对我来说毫无意义.如果要阻止某些客户端获取资源,只需返回错误代码即可.也许403适合这个? (2认同)
  • 是的,但如果我没记错的话,我在此示例中的假设是蓝图是在“__init__.py”文件中创建的。 (2认同)