DO YOU READ ME?

Digitalisierung betrifft uns alle. Doch wie meistern Organisationen die neuen Herausforderungen, die das digitale Zeitalter mit sich bringt? Worauf muss bei der Führung von Teams geachtet werden und…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




FastAPI Versioning

Whenever you're building an API, no matter its purpose, you will reach a point where a significant number of clients are using your product and you need to make changes that will break the way they are interacting with it. Another way of looking at this is that your clients will receive a different response from what they are used to, they have to use a different set of query parameters, the URL has changed, etc. This will eventually happen when you are constantly adding new features or improving the ones you already provide.

This is where API versioning shines. You can provide multiple versions of your API at the same time, and whenever you make a breaking change, you just create a new version and the clients can continue using the previous one for some time until they manage to adapt to the new one.

Even though in this article we are talking about API versioning with FastAPI (which means you should know the basics of FastAPI), we'll make a brief introduction to this python web framework.

FastAPI defines itself as:

It's built on top of Starlette (ASGI toolkit for building asyncio services) and Pydantic (Data model validation tool). Both of which make FastAPI a breeze to use, and produce very fast and reliable services.

It also provides automatic API documentation using the OpenAPI standard which is a huge plus and makes you save a lot of time.

FastAPI is not the only python web framework, nor is it the most popular one. You have other options like Django or Flask. Each one of them with its pros and cons which you'd have to consider before building your API.

You can learn more about the framework by reading the official documentation and tutorials.

If we go through the documentation in-depth, we can see they don't seem to provide a preferred way of managing different API versions at the same time. Before we explore ways to implement that versioning, we are going to take a look at the different ways versioning is generally implemented.

Developers seem torn on which approach to follow since both have their clear pros and cons. We will take a quick look at their differences.

If we strictly follow REST rules, this versioning technique would be the preferred one. This is because if we add a version to an endpoint's path (e.g. /v2/resource), this would be like a different version of the resource when in reality, you could be just changing the way you present it in the response.

To put it simply, you need to define a custom header that would be used to define which format version of the API you are requesting. For example, you could use an Accept-Version header of requests and a Content-Version header in the response.

Even though this follows REST rules, there's one major drawback, you don't get to see which version you are requesting in the URL, which makes it cumbersome to test if you are not using something like curl or Postman.

On the other hand, URL versioning is as easy as it sounds, you just need to add a version in the URL path, for example, my-api.com/v1/resource.

As explained before, this does not follow REST rules, as we are most probably versioning the request or response format and not the resource in itself. But this brings the clear advantage of knowing which version you are requesting, therefore making it easier to test and develop.

Let's say you are providing some third-party clients, an API with information about books. We'll be going through the steps for implementing such API but we'll add a v2 after the first version. In the end, the simplified file structure will look something like this:

Let’s start by taking a look at our base Book pydantic model, which represents a resource you can query from our API.

Of course, this is a very simple model. You could think of many ways to improve this, adding more information, etc. The goal of this is to start with a basic model (v1) and then improve it in later versions.

In a real application, you would have a database full of books, but in this case, we'll use a simple JSON file to store the data.

Up to this point, it looks like we are building an ordinary FastAPI service like most of the ones you've seen or worked on before. But here in the app.py file is where we start managing versions.

As you can see, we are including the same router three times. This will allow the user of the API, to access the same endpoint with three different endpoints:

This might not seem useful at first, but this will come in handy once we have multiple versions of the API endpoints.

Let's say now we want to start providing more in-depth information about the author of the book because we only have the name, but we might want to know the birthdate or the nationality of that author.

To simulate this new data around authors, we've modified the books.json file to include an author object inside each book.

This translates into the second version of the models, where we now add an Author class. Each author is represented by an ID and also has a name, birthdate, and nationality.

As you can see, in the Book class, we go from having an author represented by a simple string, to having a full Author instance inside each book.

Now we need to create the router for the new version of the API since we want to keep the old Book version for some time while clients adapt to the new one.

If we compare this router to the first version, there are not a lot of changes, we are just importing the new Book model and reading from a different JSON file. In a real-world scenario, there will usually be big differences between routers of different versions. In our case, we are only changing the model, but we could also be modifying the logic inside each endpoint. In this example, we've kept it simple for explaining purposes.

The last step is to add our new router to the app.

As simple as that, we have now two versions of our API running at the same time. You can now access v2 using "no prefix", /v2or /latest.

If you need to deprecate the old version (v1) in the future, after making sure your clients have adapted, you just need to remove the v1 router from the app, and you can clean the rest of the code.

Add a comment

Related posts:

Announcing our Ambassador Program

We are thrilled to announce the launch of our ambassador program for freelancers. You can become an ambassador today! We are building Rise with one goal in mind, to revolutionize the workplace and…