engineering

September 17, 2020   |   8min read

Will FastApi Become a New Flask?

In recent years in the world of Python frameworks, Flask and Django were the most popular. In general, Django is usually a choice for bigger applications with a wide spectrum of features. On the other hand, microframework such as Flask is popular for creating microservices. As frameworks mentioned above are easy to learn and use, have large communities around them, are time tested, and have generally more advantages, it’s not easy for new ones to get into the mainstream. But it seems there is a game-changer: asyncio. Asyncio allows you to write concurrent code using async/await syntax. It can provide substantial performance optimizations, especially for IO-bound applications. Asyncio module was introduced in Python 3.4 and was developed dynamically with every next minor Python version.

Along with it, many libraries and frameworks for taking advantage of async appeared. What about Flask and Django in the context of asyncio? Django is going to have asyncio support. Of course, it will take some time until it will be fully applied to such a big framework, but there is no other complex async framework to compete with Django. The situation is different in case of microframeworks. It’s not clear if and how Flask is going to support asyncio, you can read more about it on GitHub. On the other hand, many new microframeworks were created that don’t have to bother providing compatibility with a synchronous version which makes them able to be developed faster. Some of them are still not production-ready, abandoned, or are under heavy development. But there are also a few promising ones.

One of the most interesting is FastApi. It shows excellent performance and offers some valuable features. It’s based on Starlette and derives some features from it. FastApi works with Python 3.6+. I’ll describe the combined features of Starlette and FastApi compared to Flask capabilities.

Asynchronous path operations

One of the most significant FastApi advantages is the possibility of writing asynchronous views. Views look similar to these known from Flask. FastApi allows you to write asynchronous path operations like:

@app.get('/')
async def example_async():
	results = await async_io_operation()
	return results

Yet, it’s still possible to write synchronous views:

@app.get('/')
def example_sync():
	results sync_io_operation()
	return results

You can mix asynchronous and synchronous views. If you use a synchronous version, it’s run in an external thread pool not to block the server. Such an approach allows you to take advantage of async programming with no limitation to the synchronous one.

WebSockets

WebSocket is the communication Protocol based on TCP connection. It provides full-duplex communication channels in contrast to traditional Http connections that provide half-duplex. Websockets are useful to implement, e.g., news feed or financial tickers. Flask works with WSGI. WSGI applications are synchronous, aimed to get a request and return a response. As a consequence, WebSockets can be supported in Flask only with additional libraries like SocketIo. FastApi and Starlette implement ASGI specification. ASGI is a spiritual successor of WSGI that provides an async server/application interface, with support for HTTP, HTTP/2, and WebSockets. Thanks to that, FastApi can work with WebSockets without any additional dependencies. Working with WebSockets in FastApi is easy. An example of an endpoint may look like this:

from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/web_socket")
async def websocket_example(websocket: WebSocket):
	await websocket.accept()
	while True:
    		data = await websocket.receive_text()
    		await websocket.send_text(f"Received: {data}")

Data validation

Request data validation is a must. Incoming data may be malformed or can contain insecure values. Usually, writing data validation code from scratch can be repetitive and boring. It can lead to many lines of code, so it’s easy to make a mistake. Flask doesn’t provide automatic validation tools itself. There are additional libraries that can do validation like marshmallow (using flask-marshmallow) or schema. However, they require writing library-specific code or JSON schemas. Thanks to Pydantic, FastApi provides automatic request data validation based on pure Python code with typing. Let’s consider the following example:

from typing import Optional

from fastapi import APIRouter
from pydantic.main import BaseModel

router = APIRouter()


class Point(BaseModel):
	latitude: float
	longitude: float
	name: Optional[str] = None


@router.post("/point", response_model=Point)
def create_point(point: Point,):
	return point

This simple endpoint consumes data described by Point class and just returns what it gets. It returns an error when invalid values are sent:

requests.post('http://localhost/api/v1/point', json={'latitude': 'test'})

following JSON is returned:

{
  "detail": [
	{
  	"loc": [
    	"body",
    	"Point", 
    	"latitude"
  	],
  	"msg": "value is not a valid float",
  	"type": "type_error.float"
	},
	{
  	"loc": [
    	"body",
    	"point",
    	"longitude"
  	],
  	"msg": "field required",
  	"type": "value_error.missing"
	}
  ]
}

Data validation also works for path and query params. Let’s modify the previous endpoint a bit:

@router.post("/point/{latitude}/{longitude}",)
def create_point(latitude: float = Path(..., ge=-90, le=90), longitude: float = Path(..., ge=-180, le=180), name: Optional[str] = Query(None, max_length=50)):
	return Point(latitude=latitude, longitude=longitude, name=name)

“…” means that latitude and longitude are required path parameters. Latitude has to be more or equal to -90 and less or equal to 90. Validation is similar in the case of longitude. Name is an optional query parameter with a maximum length of 50 characters.

Pydantic allows you to write nested schemas and more strict validations. Moreover, Pydantic models can be created from ORM class objects.

Api documentation

Writing documentation by hand is another boring, error-prone, and time-consuming duty. Automatic documentation generators come with help. But again, in the case of Flask, there is a need to use external libraries. Some of them don’t work with some Flask extensions e.g., for REST API. Another FastApi benefit is automatic OpenApi documentation generation. There is no need to write additional code or install external libraries. Documentation for the endpoint above will look like:

Automatic documentation generation of FastAPI.

It’s available under /docs path. There is also a ReDoc style documentation under /redoc.

Speed

Speed is a crucial element of web applications. Choosing slow tools may be the cause of inefficient application and bad UX. Speed is one of the strongest sides of FastApi. You can read a comprehensive comparison of Flask and FastApi in this regard.

Dependency Injection

Dependency injection is a common design pattern that provides several benefits. E.g., it helps in creating loosely coupled elements and writing tests. Flask doesn’t provide a dependency injection system. If you want to use it, you have to use an extension like flask injector. FastApi provides a dependency injection system itself. Here is how you can use it to perform authentication. Note that this is a simple example just to present the dependency injection system. It’s not how authentication should be done.

def get_authenticated_user(authorization: Optional[str] = Header(None)) -> User:
	user: Optional[User] = # perform authentication here
	if not user:
    	raise HTTPException(
        	status_code=status.HTTP_401_UNAUTHORIZED,
        	detail="Invalid token",
    	)
	return user

@router.get("/get-user-name")
def get_user_name(user: User = Depends(get_authenticated_user)):
	return user.full_name

An “authorization” header defined as an argument of dependency will be automatically added to the documentation. There is no need to register dependency or put it in some kind of setting. You simply use it in your view. It’s possible to create nested dependencies. FastApi dependency should be a callable object so you can use classes as a dependency too. Dependency allows you to use “yield” in order to do some extra operations after finishing, like closing resources.

Other FastApi aspects

There are a few minor but important advantages of FastApi.

Settings

Additional feature provided by Pydantic is settings management. This feature allows you to automatically read values from environment variables, .env files, and provide default values. Furthermore, adding typing to your settings fields, you can be sure the value type is checked.

Background tasks

FastApi provides background tasks functionality. It allows you to perform some operations after returning a response. In some simple cases, it can be an alternative to more advanced tools like Celery.

Documentation

FastApi documentation looks modern and is easy to read and learn. It covers consecutive aspects of the framework in simple words, along with examples. It looks a bit similar to the Django documentation that, in my opinion, is very-well written and useful.

GraphQL

GraphQL is an alternative to REST. In some aspects, it’s more flexible than REST and can provide huge optimizations. Both Flask and FastApi provide support for the GraphQL using a graphene library.

Summary

FastApi provides many new, valuable, and convenient features. At the same time, it remains an elastic microframework style known form Flask. Will FlastApi become the new Flask? Flask still remains a good choice for many use cases. It’s well known and has gathered a big community. FastApi is still young, and it’s not yet tested by the time.

On the other hand, FastApi gives us many new and attractive features. Its community is growing fast. Switching from Flask to the FastApi doesn’t seem to be complicated. FastApi creator claims that he was inspired by Flask. He provides a rationale for creating a new framework. It covers comparisons, inspirations, and a lack of other Python frameworks. It’s worth looking at it to understand the reasons that encouraged the author to create FastApi. There is also a template for creating FastApi projects using a cookiecutter tool. Let’s give it a try!

Karol Kostrzewa

Software Engineer

Did you enjoy the read?

If you have any questions, don’t hesitate to ask!