Async Python Service With FastAPI & SQLAlchemy
Async Python Service With FastAPI & SQLAlchemy
towardsdatascience.com
Michael Azimov
9–11 minutes
Background
Before We Begin
1 of 7 9/13/2023, 11:15 AM
Build an async python service with FastAPI & SQLAlchemy | by Mich... about:reader?url=https%3A%2F%2Ftowardsdatascience.com%2Fbuil...
In this blog post we are going to build a small CRUD python app (I will be using
Python 3.9, but it should work on 3.7+). The post will focus on the
implementation and usage of FastAPI and async SQLAlchemy, and not on the
theory and general usage of AsyncIO in Python. In addition, this post assumes
you have previous knowledge in the following subjects:
1. Python language and ecosystem (venvs, IDE)
2. SQL and SQLALchemy
3. HTTP web services concepts
All of the code in this post can be found in this public repository:
https://github.com/azimovMichael/my-async-app
Initial Setup
Preparing environment
First of all, you need to create a new project with a new virtual environment.
Inside the new venv, install our first packages — FastAPI and uvicorn.
pip install fastapi uvicorn[standard]
FastAPI is a fairly new python (micro) web framework with built-in support for
async endpoints.
Uvicorn is our chosen ASGI server. ASGI Is the asynchronous sister of python
WSGI.
Now we are ready for some code.
2 of 7 9/13/2023, 11:15 AM
Build an async python service with FastAPI & SQLAlchemy | by Mich... about:reader?url=https%3A%2F%2Ftowardsdatascience.com%2Fbuil...
In your app.py file, add an async function called hello_world, and mount it to
the base GET route:
Re-run the service, and you should see two new things: In the API Docs, you
should see our new endpoint, and you can also call it using the “Try it out”
button:
3 of 7 9/13/2023, 11:15 AM
Build an async python service with FastAPI & SQLAlchemy | by Mich... about:reader?url=https%3A%2F%2Ftowardsdatascience.com%2Fbuil...
If you want to use a different DB (MySql, PostgreSQL, etc) you need to install a
compatible driver with AsyncIO support, and update the DATABASE_URL
parameter.
DB Model
We’re building a book store app, so it shouldn’t be a surprise that our main DB
table will be, you guessed it — a book. Create a new package inside the db
package, called models, and inside it a new module called book.py.
Our book entity will also have some fields — name, author and release year:
In order to create a new entity, we will use a DAL (Data Access Layer) class,
that will be responsible for all the sql functions for this DB model. Create a dals
package and a book_dal.py module in it:
We have 3 functions: A create_book function that receives our entity fields,
and saves a new record to the DB. A get_all_books function that returns all
books in the DB, and an update_book function that receives a book_id and
optionally new values for the book fields and updates them. In the
update_book functions, we are adding an execution option called
synchronize_session that tells the session to “refresh” the updated entities
using the fetch method, to make sure the entities we have in memory will be
up-to-date with the new values we updated.
Now we need some new endpoints that will use these DAL functions, so let’s
add them our app.py:
Each of the endpoints asynchronously creates a DB session, a BookDAL
instance with the session and calls the relevant function (If your “clean code”
instincts are screaming right now, that’s totally fine, we will address them in a
few paragraphs).
Pay attention to the PUT method: by using an Optional type with a default
value, we make the query parameters as optional.
But, for all of these nice stuff to actually work, we need to create our books
table. In order to do that, we will utilize FastAPI’s events feature, and create the
necessary tables on app startup (obviously, this is not something we will want
to do in a production app):
Now, you can run the app, and check the API Docs page. It should look like
this:
The API docs are interactive so you can call our new endpoints right from this
page. Create a book:
4 of 7 9/13/2023, 11:15 AM
Build an async python service with FastAPI & SQLAlchemy | by Mich... about:reader?url=https%3A%2F%2Ftowardsdatascience.com%2Fbuil...
You can use any input parameters you want. After executing the command, you
should see a new record in our books table. Now, let’s fetch it using the get
endpoint:
As you can see, our app has responded with our new book, that was given the
id 1. We can now update this book, using the update book PUT function:
5 of 7 9/13/2023, 11:15 AM
Build an async python service with FastAPI & SQLAlchemy | by Mich... about:reader?url=https%3A%2F%2Ftowardsdatascience.com%2Fbuil...
and then fetch it again, and verify that the name of the book has actually
changed:
Refactoring
Now that we have a working async app, I want to use some FastAPI features to
make the code a bit cleaner.
API Router
Currently, our app.py file contains all of our endpoints. In a real-world app, we
can have a lot more endpoints, and this file can get extremely big. In order to
avoid this, we can use FastAPI’s API Router feature. Create a routers package
and a book_router.py file in it:
The book_router.py file will contain all the http routes related to our book
entity. Now we need to update our app.py file to include this new router:
You can use the interactive API docs to verify that our endpoints work properly.
Dependencies
Did you notice all the boilerplate code we are using inside our endpoints
implementation? The DB session initialization? How nice it would be if we didn’t
have to implement it for every one of our endpoints, right? Fortunately, FastAPI
comes to our help once again!
We can use FastAPIs dependency injection capability to make the book_dal a
dependency of our endpoint. This way we only implement the creation logic of
BookDAL once, and then we can use it in every endpoint. Create a
dependencies.py file and add a get_book_dal function:
Now, we need to make this function to be a dependency of our endpoint, using
FastAPIs dependencies feature:
FastAPIs Dependency Injection feature, is very powerful yet easy to use. In our
use case we used it to inject our endpoints with DAL classes, but we could
inject a lot of other things — security components, BL components, etc.
6 of 7 9/13/2023, 11:15 AM
Build an async python service with FastAPI & SQLAlchemy | by Mich... about:reader?url=https%3A%2F%2Ftowardsdatascience.com%2Fbuil...
Conclusion
Python asyncio is relatively new, and there are a lot of complexities and other
interesting use cases that we didn’t cover, and I encourage everyone of you to
explore this new and exciting world.
FastAPI is a new and modern web framework that puts emphasis on speed,
ease of use and of course — built-in support for AsyncIO.
In this post, we’ve build a fully async python app — from async http endpoints
using FastAPI to async DB queries using SQLAlchemy 1.4. A very important
topic that we didn’t cover in this post, and I’m looking forward to write about it in
my next post, is testing async endpoints and code.
7 of 7 9/13/2023, 11:15 AM