Introduction
For the last post in the series, I'll briefly talk about deploying FastAPI to Heroku. Additionally, I'll talk about adding environment variables into our app that it may depend on.
Getting Started
You'll need an account on Heroku to spin up a server for deployment. Additionally, you'll need a Github account because we are deploying from Github.
Github
Create a new repository on Github and follow the directions to push an existing project to the new repository.
You'll have to commit all the changes before pushing the code upstream.
Heroku
On Heroku, create a new app and give it a unique name.
On the next screen, connect Heroku to your Github account. This allows the app to update after you push new code.
Give Heroku the permissions it needs, then—I recommend—doing automatic deploys. Make sure you're deploying from your main or master branch.
You can run a manual deployment, but your app will fail. We have to add a couple of files and environment variables.
Deployment Configuration
requirements.txt
To generate the file, open up a new terminal and activate your Python environment. Run the command pip freeze > requirements.txt
. This collects the project dependencies and the versions used. The first time I did this, I had a couple of packages that gave me trouble a few weeks ago. Unfortunately, I don't remember which ones they were! Therefore, I'll post my requirements.txt
.
appdirs==1.4.4
black==20.8b1
certifi==2020.12.5
chardet==4.0.0
click==7.1.2
fastapi==0.63.0
gunicorn==20.0.4
h11==0.12.0
httptools==0.1.1
idna==2.10
joblib==1.0.1
mypy-extensions==0.4.3
numpy==1.19.5
pandas==1.1.5
pathspec==0.8.1
pydantic>=1.8,<2.0.0
python-dateutil==2.8.1
pytz==2021.1
regex==2020.11.13
requests==2.25.1
scikit-learn==0.24.1
scipy==1.5.4
six==1.15.0
sklearn==0.0
starlette==0.13.6
threadpoolctl==2.1.0
toml==0.10.2
typed-ast==1.4.2
typing-extensions==3.7.4.3
urllib3==1.26.4
uvicorn==0.13.4
uvloop==0.15.1
runtime.txt
Next, we need to specify the Heroku runtime and Python version.
Create a new file in the project root named runtime.txt
. Inside the file, enter the text:
python-3.9.0a
Procfile
The final file is the famous Heroku Procfile
.
Here we define the starting command for our web application. Consequently, we have the opportunity to inject our environment variables into the app.
web: SANITY_API_KEY=$SANITY_API_KEY API_KEY=$API_KEY ENV="production" gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
This is all one statement, but it's composed of different parts.
The first part is the list of environment variables:
SANITY_API_KEY=$SANITY_API_KEY API_KEY=$API_KEY ENV="production"
The syntax $variable
means that this is an environment variable relative to the server. We can define these in the Heroku instance settings.
These values depend on your application.
The second part is for starting our application:
gunicorn -w 4 -k uvicorn.workers.UvicornWorker
I cannot remember if gunicorn
and uvicorn
were installed in the application, but they may need to be downloaded. If so, generate or add them to the requirements.txt
file. The workers part is beyond the scope of this series.
The last part, main:app
, is the location of the FastAPI object in the project. For us, this is inside the main.py
file. And the object's name is app
.
Save the files and push them to your Github repository. This should trigger a build for your Heroku app. Now when you visit the app, you should see your index route and see your docs at /docs
.
If you're like me, you need to update your host header security in main.py
. I currently am seeing the response Invalid host header
.
Conclusion
This article series took longer than I planned! Unfortunately, I wasn't able to get into the topic of API management partly because it took longer and partly because the Azure API Management deployment cost more than I wanted to pay.
Although it wasn't a deep dive into the actual code, I hope what was covered is helpful!