FastAPI for everyone

FastAPI for everyone

Here’s why you should use FastAPI if you're building an API in python

Data science is a multidisciplinary field and this versatility brings about people from different backgrounds. Many data scientists are not equipped with a software engineering background and those are not necessarily experts. If you are a data scientist you might have tried or learned about what happens to a model after you are done with training. Particularly about taking your machine learning model to production. This is the stage in which the machine learning model is wrapped in an API to be available as a web service. Even in the case of you coming here from a web-development background, this is still relevant to you.

FastAPI is a web framework for building a python API that is fast and reliable. It's truly a good addition to your skills and special power when deploying your model falls under your responsibilities. In this preview, I would share a few advantages of using the framework over Flask.

I assume you have a brief background on APIs. For example, you can understand what endpoint, request, or query is. If you don't have any idea, you still can follow up to learn about FastAPI but do your research afterwards.

Intuitive code

Your time is precious and writing a lot of code means higher chances of bugs and errors. There are two ways in which FastAPI reduces the amount of code you type. The first is for reading parameters and the second is for data validation.

Reading parameters

This is my favourite part of FastAPI and for one obvious reason, it builds up to more and more awesomeness. One of the ways to define variables in FastAPI is the path in the same fashion as python strings:

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id):
    return {"item_id": item_id}

Reading the variables and declaring them in the path like python strings is the pythonic way. This is also not unique to FastAPI, but as you read further you will see how it builds up to make a great combination of advantages. If you declared any function parameter that is not in the path, it's automatically understood and treated as query parameter. Let's see the simple script here:

from typing import Union
from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: str, query_param: Union[str, None] = None):
    if query_param:
        return {"item_id": item_id, "query_param": query_param}
    return {"item_id": item_id}

The function read_item has one variable parameter which is item_id and another query parameter which is query. The way it's written here - =None-is just to say the query parameter is optional.

Automatic data validation

Data coming to your API can be in many shapes and formats. Validating the data before processing is important and FastAPI does this via pydantic. Pydantic streamlines data validation via python type annotations. The way this is implemented is via several methods for example in the case of query parameter we can have additional string validations. In the following script observe how we define a default value with a max_length of 6 characters.

from typing import Union
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(query_param: Union[str, None] = Query(default="FooBar", max_length=6)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if query_param:
        results.update({"query_param": query_param})
    return results

The developer can as well add numeric validation for path parameters and other, documentation. The other way is also possible simply by using the pydantic BaseModel class which defines the parameters and their data type.

from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: List[str] = []

@app.post("/items/", response_model=Item)
async def create_item(item: Item):
    return item

Look at the 3rd raw (counting from the bottom up) which is the decorator and observe that we have defined response_model as a parameter there. The value passed is the name of the BaseModel so FastAPI is going to use this to:

  • Convert the output data to the declared type.
  • Perform data validation.
  • Generate a JSON Schema for the response.
  • Use it for the automatic documentation systems.

Auto Documentation

The interactive documentation is automatically generated which is provided by swagger-ui. For example, if you are running fastapi locally you can access the docs from http://127.0.0.1:8000/docs. Which will look like this: swagger-ui doc (Image by FastAPI documentation)

You also have another optional alternative doc by redoc from http://127.0.0.1:8000/redoc which will look like this: alternative docs (Image by FastAPI documentation)

Performance

According to techempower, FastAPI is the third fastest python framework coming under Uvicron and starlette which are the backbone of FastAPI. However, I believe this is not the only speed we should care about. The speed of development and building with FastAPI is outstanding.

Conclusion

I hope this draws the image clearer in terms of how concise and elegant the building experience with FastAPI is. This is in addition to the speed and other features I shared with you here. I came across this framework back in 2019 and have been using it for several data science projects in production. There are more points that I didn't cover here because am sure you will have a pleasant time going through the FastAPI documentation. It's one of the best-documented projects out there.

Did you find this article valuable?

Support Fares Hasan by becoming a sponsor. Any amount is appreciated!