Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
43 views

Async Python Service With FastAPI & SQLAlchemy

The document describes how to build an asynchronous Python web service using FastAPI and SQLAlchemy. It covers setting up the project, creating an initial async endpoint, building out the application to include CRUD functionality for a bookstore using SQLAlchemy models and a PostgreSQL database, and connecting the database using SQLAlchemy's new async support.

Uploaded by

Leon
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
43 views

Async Python Service With FastAPI & SQLAlchemy

The document describes how to build an asynchronous Python web service using FastAPI and SQLAlchemy. It covers setting up the project, creating an initial async endpoint, building out the application to include CRUD functionality for a bookstore using SQLAlchemy models and a PostgreSQL database, and connecting the database using SQLAlchemy's new async support.

Uploaded by

Leon
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Build an async python service with FastAPI & SQLAlchemy | by Mich... about:reader?url=https%3A%2F%2Ftowardsdatascience.com%2Fbuil...

towardsdatascience.com

Build an async python service with FastAPI &


SQLAlchemy

Michael Azimov
9–11 minutes

Build a fully asynchronous python service, including async


DB queries, using FastAPI and the new SQLAlchemy AsyncIO
support

Photo by John Cameron on Unsplash

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

Async programming and python AsyncIO


Asynchronous programming is a pattern of programming that enables code to
run separately from the main application thread. Asynchronous programming is
used in many use-cases such as event-driven systems, highly scalable apps,
and many more.
Asynchronous programming is not a new concept. It’s been around for a while,
especially in the JavaScript ecosystem. Python 3.4 introduced asyncio package,
that implements python support for the Async/Await design. There are plenty
examples and tutorials about it, but some of my favorite are: Introduction to
async programming in python, Multitasking Is Not My Forte, So How Can I
Blame Python? (by my colleague ) and Concurrent Burgers — Understand
async / await (by the creator of FastAPI )

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.

First async endpoint


To configure a FastAPI service, create a python module named app.py, with the
following code:
This code isn’t doing much. It’s starting a FastAPI application, using uvicorn
ASGI server, on port 1111, without any custom endpoints. FastAPI comes with
out-of-the-box support for OpenAPI Docs, so you can run the app and go to:
http://127.0.0.1:1111/docs in your browser. If everything went well, you should
see a web page similar to this:

Initial view of the auto-generated API Docs


Now we are ready to create our first async endpoint.

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:

Docs for our new endpoint


You can also go to http://127.0.0.1:1111/, and see the “hello_world” response
text in our browser.
We have our first async endpoint!

Book store CRUD app


So, the purpose of this post is to build a small CRUD app. For demonstrations
purposes we’ll build a simple book store app, with the ability to create, update
and fetch books.

SQLAlchemy and AsyncIO


In order to use a DB for storing the books, I’m using Python’s SQLalchemy
library with an sqlite dialect that supports asyncio (aiosqlite)
Install the necessary packages:
pip install SQLAlchemy==1.4.3 aiosqlite
SQLAlchemy 1.4.X is a pretty new release, with lots of upgrades and new
features (a first step towards the highly anticipated 2.0 version), that are
detailed here. In this post, I will mainly focus on the new async support.
SQLAlchemy Asyncio should be considered alpha level in early 1.4
releases (!).
Once we’ve installed SQLAlchemy, we need to configure our DB connection.
Create a new python package named db and a new module inside it, called
config.py:
Our DB server is a local instance of SQLLite (a local test.db file) and we will
talk to it using the aiosqlite dialect that supports async queries. We are
creating the db engine using the new create_async_engine function. The
session maker is created with two unique flags: expire_on_commit=False
makes sure that our db entities and fields will be available even after a commit
was made on the session, and class_=AsyncSession is the new async
session. We’ll also use the good, old, declarative_base to configure our
soon-to-be-created DB models.

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:

Congratulations, you’ve created your first fully async python service!

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...

Verify that our endpoints still work, and that’s a wrap!

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

You might also like