Configuring Python FastAPI with SqlAlchemy and Alembic

FastAPI is a promising framework to build high performance web applications that needs Async support. It also brings in best practices for a high quality production application.

Let’s take a quick view of few building blocks that we will use in this article.

FastAPI

FastAPI is build using two important framework for well defined responsibilities :

To run FastAPI based application we will need an ASGI server such as Uvicorn or Hypercorn.

Starlette

Starlette is a lightweight ASGI framework/toolkit, which is ideal for building high performance asyncio services.

Pydantic

pydantic enforces type hints at runtime, and provides user friendly errors when data is invalid. We can define how data should be in pure python and validate it easily with pydantic.

ASGI specification

ASGI (Asynchronous Server Gateway Interface) is a spiritual successor to WSGI, intended to provide a standard interface between async-capable Python web servers, frameworks, and applications.

Uvicorn server

Uvicorn is a lightning-fast ASGI server, built on uvloop and httptools.

Alembic

Alembic is a lightweight database migration tool for usage with the SQLAlchemy Database Toolkit for Python

Getting started

Let’s install only libraries that we will use:

# Use python 3.6+
pipenv install fastapi uvicorn sqlalchemy alembic

Uvicorn installation error

On doing the above installation of uvicorn, in my case resulted in an error. One of the dependency of uvicorn → unicorn errored out saying :

ERROR: Cannot use 'python', Python 2.4 or later is required.", '           Note that Python 3 or later is not yet supported.'

But uvicorn seems functional though installation had an error. I didn’t fully understand the reason., But it is not blocking our project.

Environment based configuration

pipenv install python-dotenv

Directory structure (end result )

.
├── Dockerfile
├── Pipfile
├── Pipfile.lock
├── README.md
├── alembic.ini
├── app
│ ├── __init__.py
│ ├── config
│ │ ├── __init__.py
│ │ ├── prod.env
│ │ └── qa.env
│ ├── database.py
│ ├── main.py
│ ├── models
│ │ ├── __init__.py
│ └── schemas
├── migration
│ ├── README
│ ├── env.py
│ ├── script.py.mako
│ └── versions
│ └── 66d8a54cd297_initial_tables.py
├── start.sh

Create a directory config and have environment configurations there.

#__init__.py
from pydantic import BaseSettings
class Settings(BaseSettings):
# default conf goes here
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50
class Config:
env_file = ".env"

Alembic

# Initialize alembic database migration flow
$ alembic init db-migration
  • Update alembic’s env.py with environment based db_url with custom get_url method as shown below
env.py

Alembic autogeneration of migration scripts

  • For autogeneration to work, alembic should be able to detect all models that we have in the application.

We make use of autogeneration of schema changes. With this, we can make changes to database models and run autogenerate — this will generate the changes as script.

# This will scan the models and generate upgrade & downgrade scripts
alembic revision --autogenerate -m “Initial tables”

Running db migration

Detailed information on alembic commands can be found here.
Here is a quick reference:

# following command will run all migration script and bring it to latest version
alembic upgrade head
# If we like to incrementally upgrade and check for some errors
alembic upgrade +1
# To undo last migration
alembic downgrade -1
# To get more information
alembic current
alembic history - verbose

Summary

  • SQLAlchemy Model creation is well documented in fastapi documentation. So this article is not diving into those details.

Useful links

Software Architect ★ Data engineer ★ Committed to improve data science productivity

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store