Deploying to Heroku with FastAPI + SQLAlchemy (Postgres)
TL;DR
FastAPI is a very convenient micro web framework for building RESTful APIs in Python, and it also excels in performance. It also has type support, and the automatic generation of API documentation via Swagger UI is excellent.
When actually building an API, Heroku is free to use and easy to deploy to, making it invaluable for creating test servers. Since Heroku only supports Postgres SQL in its free tier, if you want to incorporate a database, you inevitably need to use Postgres.
While there are articles that describe how to use it, there weren't many focused simply on just deploying, so I wrote this.
Dependencies
We use sqlalchemy as the ORM. We also use psycopg2-binary to connect to Postgres. I personally use pipenv, so I'll prepare a Pipfile. Additionally, I want post data to be typed, so I'll use pydantic.
Pipfile
Test-Running FastAPI
Install the dependencies. I personally always create Python files under an app/ directory, so I'll do the same this time.
app/main.py
Let's start it up.
If you can see {"message": "Hello World"} at https://localhost:8002, you're good to go.
Setting Up the Local Environment
We'll use docker to enable local testing including the database.
Dockerfile
docker-compose.yml
Model Definition
Define the model for SQLAlchemy. This time we'll create a TODO table. We want the table to be created automatically, so we use:
app/model.py
to create it.
Also, since there's no _asdict method, we define our own function to convert to a dictionary.
app/model.py
We define POST and GET operations for TODO. For the Post operation, since we want title and description to always be in the request body, we define a Data class using pydantic.
app/main.py
Access http://localhost:8002/docs and test Get and Post using the Swagger UI. Here's the commit up to this point.
Deploying to Heroku
Create a project using your preferred method and enable the Postgres SQL add-on.
One gotcha is that when you add the Postgres SQL add-on on Heroku, it provides a DATABASE_URL as an environment variable, but you can't just pass it directly to create_engine. The reason is that DATABASE_URL looks like postgres://...., but create_engine requires it to be postgresql://....
Taking this into account, let's rewrite create_engine.
Something like that.
Next, write the Procfile.
Procfile
After that, just deploy and you're done.
Conclusion
FastAPI is great to have types with. The finished product is available on GitHub.