The “FastAPI” Experience
By: Surya Kant Bansal
Tags: API, Full Stack, Servers, Python3, Fastapi

If we talk about application development in Python, most people would think about Flask and Django. These two frameworks are the most widely used frameworks in Python. Now, there is a new framework available called “FastAPI”, which is extremely powerful and very easy to learn and it might become even more popular than Flask and Django. This framework was developed by Sebastián Ramírez in late 2018 and has been continuously under development ever since.

Groundwork

For writing application backend, I have always used the Flask framework. And so far my experience with Flask has been just fine, its a pretty simple and straight forward framework that you can use to write simple APIs. You can check out my Github Profile to find some pretty cool applications written in Flask. I have used it for small as well as large backend server and I have not had any problems so far.

This time, I was going to write a billing and inventory management application and I decided to use this new FastAPI framework that was becoming really popular because of its ease of use, scalability and speed. I started out by reading the FastAPI Tutorial which took me through setting up and running a basic API. After that, I went over the documentation to understand the multiple ways in which I can create and modify APIs according to my needs. I also looked over the way FastAPI creates API documentation for you automatically which is a great feature in my opinion if you are writing large scale applications. The best thing about working with FastAPI is that you only need to focus on your APIs, you do not need to worry about documentation and the request & response configuration.

Beginning Development

I started out by writing my APIs in a single file and creating the database models using the SQLAlchemy ORM. Let's talk about an example API:

app = FastAPI() @app.post("/products", response_model=schemas.ProductResponse)

def create_product(*, db: Session = Depends(get_db), product_in: schemas.ProductCreate):

"""

Create new products.

"""

product = crud.product.get_by_tag_id(db, tag_id=product_in.tag_id)

if product:

raise HTTPException(

status_code=status.HTTP_400_BAD_REQUEST,

detail="The product with this tag_id already exists in the system.",

)

product = crud.product.create(db, obj_in=product_in)

return product

There are a couple of things here that you might not understand just yet. An app instance can be created from the FastAPI class. I have declared a POST route on the /products endpoint using the app.post wrapper. FastAPI uses Python Typings which can be used to set API response_model which is used by FastAPI to generate related documentation. Pydantic is another Python library that can be used to declare custom models. In the snippet, you can see ProductResponse & ProductCreate are custom defined pydantic model. Depends is a dependency injection module provided by FastAPI. I have used it here to inject the db session which is provided by the get_db function. I have declared a product_in function argument and set its type to the ProductCreate pydantic model. Now what FastAPI does for you is that you do not need to worry where and how to get the data from the request, it will automatically verify the data received in the request with the model that you provided before running your API function. The function docstring will also be used in the API documentation. crud is just a simple module that I wrote for database interactions to make my application more organised. To return a response, you just need to return a variable that matches the response_model that you set for the API and all the response headers will be taken care of by FastAPI. If you want to throw a failed API response, you can just raise an HTTPException which is available in the fastapi framework itself. FastAPI uses Uvicorn as its ASGI server. Once you start your application using Uvicorn, you can check your API documentation with Swagger at /docs or with Redoc at /redoc .

Project Structure

Once you have your project mapped out, your project structure should be one that can be scaled easily. You APIs, files and modules should all be organised so that its easier to collaborate on it. With this notion in mind, I looked at Full-Stack FastAPI templates that are provided in the documentation. These templates are a really good starter templates for scalable and production-ready projects. They take care of all the aspects of a Full-Stack project, from the development phase to production deployment.

But I knew if I used this template, it would be a lot difficult for me to completely understand how my application works because there were a lot of modules used by the template that I had never even heard of. Which is why I decided to go my own way, creating a project structure of my own and just get an idea of how my application structure should look like from the template’s structure.

Structure:

After reading most of the documentation and getting ideas from the templates provided in the documentation, I came up with the following project structure:

- root

- app

- api

- core

- crud

- database

- enums

- models

- schemas

- tests

- main.py

- initialiser.py

- migrations

- Pipfile

- Pipfile.lock

- prestart.sh

- README.md

- alembic.ini

I would not go over the code too much but I am going to explain this project structure. The root directory contains the app and migrations directories. I am using pipenv as my dependency manager. alembic.ini is a configuration file for the alembic python package that is used to generate and maintain database migrations. All the database migrations generated by alembic are kept inside the migrations directory. The app directory contains the main project codebase. I have also written a prestart.sh shell script which should be run before running the Uvicorn server. This script runs all the database migrations and runs the app/initialiser.py file that creates initial data in the database.

Now let’s go over the app directory from the top. The api module contains all implemented APIs exported in the form of FastAPI routers. The core module contains the application configuration and security files. The crud module contains the CRUD models for each database table, which act as a primary database operations model for the entire project. The database module contains the base ORM classes which will be used to declare SQLAlchemy models and a database session accessor. The enums module contains project-wide common enums. The models module contains the SQLAlchemy ORM models corresponding to the database tables. The schemas module contains custom Pydantic models relevant to the APIs and CRUD objects. The tests module contains the pytest configuration and the unit test cases for the application APIs and CRUD objects. The main.py file imports all the routers from the api module, attaches them to the main application and then runs the application using Uvicorn.

Results:

I created this project structure while I was implementing my application which is why I was aware of all the packages I installed in my application and I completely understood how my entire application was working. After finishing this setup, the further development of this application became a lot easier. As the FastAPI setup uses Uvicorn server, you don’t need to take any extra steps for production deployment, your Uvicorn server will also work for production. Head over this Uvicorn Deployment documentation to understand how that works.

Future Endeavours

Whenever I work on an application using any new technology, I always tend to extract a boilerplate from that application which helps in getting a headstart for any new project that might come my way in the future. In my personal opinion, I always find it a lot helpful to create a project boilerplate because I have experienced situations in which I had to rework on the project setup just because I did not keep track of the steps I took while setting up a project.

Conclusion

The result of all my hustle with writing an application using FastAPI framework is a minimal dependency and scalable template repository which can be used to start new FastAPI projects. So head over to this repository if you want a headstart on your FastAPI project.

Thank you for reading this!