Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Support multiple API versions in flask

Tags:

python

flask

I started to design a RESTful webservice with Flask and Python and I'm wondering how one would support multiple API versions in the same project. I'm thinking of putting the requested API version in the URL like this:

/myapp/v1/Users 

After some time I want to add another endpoint in Version 1.1 of the API and keep everything from v1 which did not change:

/myapp/v1.1/Users   <= Same as in v1 /myapp/v1.1/Books 

In v2 the "Users"-endpoint is changed:

/myapp/v2/Users   <= Changed in v2 /myapp/v2/Books   <= Same as in v1.1 

and so on...

Looking at this question the easiest way probably would be something like this:

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

But I can imagine that this will get harder to maintain with each new API version. Therefore I was wondering if there's any better (= easier to maintain and better structured) way to achieve this with Flask?

like image 593
Keeper Avatar asked Mar 01 '15 15:03

Keeper


People also ask

Does Flask support REST API?

Flask Restful is an extension for Flask that adds support for building REST APIs in Python using Flask as the back-end. It encourages best practices and is very easy to set up. Flask restful is very easy to pick up if you're already familiar with flask. In flask_restful , the main building block is a resource.


2 Answers

I am the author of the accepted answer on the question you referenced. I think the /<version>/users approach is not very effective as you say. If you have to manage three or four different versions you'll end up with spaghetti code.

The nginx idea I proposed there is better, but has the drawback that you have to host two separate applications. Back then I missed to mention a third alternative, which is to use a blueprint for each API version. For example, consider the following app structure (greatly simplified for clarity):

my_project +-- api/     +-- v1/         +-- __init__.py         +-- routes.py     +-- v1_1/         +-- __init__.py         +-- routes.py     +-- v2/         +-- __init__.py         +-- routes.py     +-- __init__.py     +-- common.py 

Here you have a api/common.py that implements common functions that all versions of the API need. For example, you can have an auxiliary function (not decorated as a route) that responds to your /users route that is identical in v1 and v1.1.

The routes.py for each API version define the routes, and when necessary call into common.py functions to avoid duplicating logic. For example, your v1 and v1.1 routes.py can have:

from api import common  @api.route('/users') def get_users():     return common.get_users() 

Note the api.route. Here api is a blueprint. Having each API version implemented as a blueprint helps to combine everything with the proper versioned URLs. Here is an example app setup code that imports the API blueprints into the application instance:

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') 

This structure is very nice because it keeps all API versions separate, yet they are served by the same application. As an added benefit, when the time comes to stop supporting v1, you just remove the register_blueprint call for that version, delete the v1 package from your sources and you are done.

Now, with all of this said, you should really make an effort to design your API in a way that minimizes the risk of having to rev the version. Consider that adding new routes does not require a new API version, it is perfectly fine to extend an API with new routes. And changes in existing routes can sometimes be designed in a way that do not affect old clients. Sometimes it is less painful to rev the API and have more freedom to change things, but ideally that doesn't happen too often.

like image 165
Miguel Avatar answered Oct 31 '22 23:10

Miguel


if its still relevant I wrote a package to manage endpoints by versions You can find it on Git https://github.com/itay-bardugo/flask_version

like image 34
Itay Bardugo Avatar answered Oct 31 '22 22:10

Itay Bardugo