我开始使用Flask和Python设计一种RESTful Web服务,我想知道如何在同一项目中支持多个API版本。我正在考虑将请求的API版本放在这样的URL中:
/myapp/v1/Users
一段时间后,我想在API版本1.1中添加另一个端点,并保留v1中所有未更改的内容:
/myapp/v1.1/Users <= Same as in v1 /myapp/v1.1/Books
在v2中,“用户”端点已更改:
/myapp/v2/Users <= Changed in v2 /myapp/v2/Books <= Same as in v1.1
等等…
看着这个问题,最简单的方法可能是这样的:
@app.route('/<version>/users') def users(version): # do something return jsonify(response)
但是我可以想象每个新的API版本都将很难维护它。因此,我想知道Flask是否有更好的方法(更易于维护和结构化)来实现这一目标?
我是你所提及问题的被接受答案的作者。我认为这种/<version>/users方法不是你所说的那么有效。如果你必须管理三个或四个不同的版本,则最终将得到意大利面条代码。
/<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
在这里,你可以api/common.py实现所有API版本所需的通用功能。例如,你可以具有一个辅助功能(未装饰为路线),该功能可以响应你/users在v1和v1.1中相同的路线。
api/common.py
/users
的routes.py每个API版本定义的路由,并在必要时调用放入common.py功能,以避免重复的逻辑。例如,你的v1和v1.1 routes.py可以具有:
routes.py
common.py
v1.1 routes.py
from api import common @api.route('/users') def get_users(): return common.get_users()
注意api.route。这api是一个蓝图。将每个API版本实现为蓝图有助于将所有内容与正确的版本化URL结合在一起。以下是将API蓝图导入到应用程序实例中的示例应用程序设置代码:
api.route
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')
这种结构非常好,因为它使所有API版本保持独立,但它们由同一应用程序提供。另外一个好处是,当需要停止支持v1时,只需删除该register_blueprint版本的调用,v1从源中删除该软件包即可。
register_blueprint
现在,说了这么多,你应该真正以最小的方式来设计API,以最大程度地减少版本修订的风险。考虑到添加新路由不需要新的API版本,最好用新路由扩展API。有时可以以不影响旧客户端的方式设计现有路由的更改。有时候,修改API的痛苦会较小,而拥有更改事物的更多自由,但是理想情况下,这种情况不会经常发生。