You should start using FastAPI now

Tivadar Danka small portrait Tivadar Danka
FastAPI logo

Understanding math will make you a better engineer.

So, I am writing the best and most comprehensive book about it.

Python has always been a popular choice for developing lightweight web apps, thanks to awesome frameworks like Flask, Django, Falcon, and many others. Due to Python's position as the number one language for machine learning, it is particularly convenient for packaging models and exposing them as a service.

For many years, Flask was the number one tool for the job, but there is a new challenger in town, in case you haven't heard. FastAPI is a relatively new web framework for Python, taking inspiration from its predecessors, perfecting them, and fixing many of their flaws. Built on top of Starlette, it brings a ton of awesome features to the table.

It has gained significant traction recently, and after spending the last year working with it every day, I can confidently say that the hype is justified. If you haven't tried it yet, I would like to give you five reasons to give it a shot.

1. Simple yet brilliant interface

All web frameworks need to balance between functionality and giving freedom to the developer. Django is powerful yet very opinionated. On the other hand, Flask is low-level enough to provide a large degree of freedom, but a lot is left for the user to do. FastAPI is more on the Flask side of the spectrum, but it strikes a healthier balance.

To give you an example, let's see how an endpoint is defined in FastAPI.

from fastapi import FastAPI
from pydantic import BaseModel


class User(BaseModel):
 email: str
 password: str


app = FastAPI()


@app.post("/login")
def login(user: User):
 # ...
 # do some magic
 # ...
 return {"msg": "login successful"}

For defining the schema, it uses Pydantic, which is another excellent Python library used for data validation. This is simple to do here, yet so much is happening in the background. The responsibility to validate the input is delegated to FastAPI. If the request is incorrect, for instance, the email field contains an int, a FastAPI app will return an appropriate error code instead of breaking down with the dreaded Internal Server Error (500). And it is practically free.

We can serve this simple example app with uvicorn:

uvicorn main:app

Now the app is ready to accept requests. In this case, a request would look like

curl -X POST "http://localhost:8000/login" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"email\":\"string\",\"password\":\"string\"}"

The icing on the cake is that it automatically generates the documentation according to the OpenAPI using the interactive Swagger UI.

Swagger UI for FastAPI Swagger UI for the FastAPI app

Async

One of the biggest disadvantages of Python WSGI web frameworks compared to those in Node.js or Go was the inability to handle requests asynchronously. Since the introduction of ASGI, this is no longer an issue, and FastAPI is taking full advantage of this. All you have to do is simply declare the endpoints with the async keyword like this:

@app.post("/")
async def endpoint():
 # ...
 # call async functions here with `await`
 # ...
 return {"msg": "FastAPI is awesome!"}

Dependency injections

FastAPI has a really cool way to manage dependencies. Although it is not forced on the developer, it is strongly encouraged to use the built-in injection system to handle dependencies in your endpoints.

To give an example, let's write an endpoint where users can post comments for certain articles.

from fastapi import FastAPI, Depends
from pydantic import BaseModel


class Comment(BaseModel):
 username: str
 content: str


app = FastAPI()


database = {
 "articles": {
 1: {
 "title": "Top 3 Reasons to Start Using FastAPI Now",
 "comments": []
 }
 }
}


def get_database():
 return database


@app.post("/articles/{article_id}/comments")
def post_comment(article_id: int, comment: Comment, database = Depends(get_database)):
 database["articles"][article_id]["comments"].append(comment)
 return {"msg": "comment posted!"}

FastAPI automatically evaluates the get_database function at runtime when the endpoint is called, so you can use the return value as you wish. There are (at least) two good reasons for this.

  1. You can override the dependencies globally by modifying the app.dependency_overrides dictionary. This can make testing a breeze since you can mock objects quickly.
  2. The dependency (the get_database in our case) can perform more sophisticated checks, allowing you to separate them from business logic. This greatly simplifies things. For instance, user authentication can be easily implemented with this technique.

Easy integration with databases

SQL, MongoDB, Redis, or whatever you choose, FastAPI doesn't force your hand to build your application around it. If you have ever tried to work with MongoDB using Django, you know how painful it can be. With FastAPI, you don't need to go the extra mile; adding a database to your stack is as simple as possible. (Or, to be more precise, the amount of work to be done will be determined by the database you choose, not by the complications added by the web framework.)

But really, look at this beauty.

from fastapi import FastAPI, Depends

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker


engine = create_engine("sqlite:///./database.db")
Session = sessionmaker(bind=engine)


def get_db():
 return Session()


app = FastAPI()


@app.get("/")
def an_endpoint_using_sql(db = Depends(get_db)):
 # ...
 # do some SQLAlchemy
 # ...
 return {"msg": "an exceptionally successful operation!"}

Voila! I can see you typing

pip install fastapi

into your terminal already.

GraphQL support

When you are working with a complex data model, REST can be a severe hindrance. It is definitely not fun when a tiny change in the frontend requires updating the schema for an endpoint. GraphQL shines in these situations. Although GraphQL support is not unique among Python web frameworks, Graphene and FastAPI work together seamlessly. No need to install any extensions like graphene_django for Django. It just works natively.

+1: Great documentation

Of course, a great framework cannot truly shine without an equally great documentation. Django, Flask, and all the others excel in this aspect, but FastAPI is on par with them. Of course, since it is much younger, there are no books written about it yet, but it is just a matter of time.

To summarize, whether you are looking for a fast and lightweight framework to serve your deep learning models or something more complex, FastAPI delivers. If you haven't tried it yet, I strongly encourage you to do so. I am pretty sure you'll stick with it.

Having a deep understanding of math will make you a better engineer.

I want to help you with this, so I am writing a comprehensive book that takes you from high school math to the advanced stuff.
Join me on this journey and let's do this together!