Daniel Easterman
Posted on July 10, 2024
In the world of Python frameworks, FastAPI is the new kid on the block and a great choice for building APIs. Equally, Render is a good option for developers who want to quickly test their applications in a production environment for free.
In this post, we'll run through how to deploy a FastAPI app to Render. First, though, let's explore why FastAPI and Render are often chosen by developers.
Why FastAPI?
FastAPI is a high-performance microframework used primarily for building APIs (the clue is in the name). As such, FastAPI offers several advantages over older, better-known frameworks such as Django and Flask.
The first and most obvious advantage of FastAPI is that it was built with scalability and performance in mind.
For example, FastAPI is based on an asynchronous ASGI server rather than the older WSGI used by Django and other frameworks. ASGI servers can handle multiple requests simultaneously (concurrently). This is often seen as a better option for apps that need to handle high levels of user traffic.
FastAPI also makes it easier for developers to write asynchronous code by simply using the async
keyword when defining asynchronous functions.
But FastAPI's shiny "newness" is also its main drawback. Because it was only introduced in 2018, FastAPI has a much smaller community and fewer learning resources (such as coding tutorials) compared to the more established frameworks. This is something to bear in mind when choosing FastAPI for your next project.
Why Render?
Render is a great option for developers who want to quickly test their applications in a production environment for free.
With Render, you don't even have to enter your credit card details to gain access to the free tier. So unlike other cloud services, there is no way to rack up charges by mistake.
As we will see in the section below, Render also provides an excellent overall developer experience with a clean, very easy-to-use UI and smooth integration with Git and GitHub. An added bonus is that any app you host on Render gets a free TLS certificate right out of the box.
The downside with Render's free tier is that it can take a long time for deployments to complete. Once this starts to become an issue, you might want to consider upgrading to one of the paid plans.
Create a FastAPI Demo Application
You can view, download, or clone the full code used in this article.
The first thing we need to do is create an empty directory where our project will live. Let's call it fastapi-render-appsignal
.
Run the following commands in your terminal:
mkdir fastapi-render-appsignal
cd flask-heroku-appsignal
touch main.py
The entry point for the project will be main.py
.
Next, we need to make our project a git repository by running the git initialize command in the root of the directory:
git init
Also, create a requirements.txt
file in the project's root directory. Add these two lines to the file:
fastapi
uvicorn[standard]
Then run:
pip install -r requirements.txt
If the installation goes smoothly, you should see the following output in the terminal:
Installing collected packages: websockets, uvloop, typing-extensions, sniffio, pyyaml, python-dotenv, idna, httptools, h11, exceptiongroup, click, annotated-types, uvicorn, pydantic-core, anyio, watchfiles, starlette, pydantic, fastapi
Successfully installed annotated-types-0.6.0 anyio-4.2.0 click-8.1.7 exceptiongroup-1.2.0 fastapi-0.109.0 h11-0.14.0 httptools-0.6.1 idna-3.6 pydantic-2.5.3 pydantic-core-2.14.6 python-dotenv-1.0.1 pyyaml-6.0.1 sniffio-1.3.0 starlette-0.35.1 typing-extensions-4.9.0 uvicorn-0.27.0 uvloop-0.19.0 watchfiles-0.21.0 websockets-12.0
Now, in main.py
, copy and paste the following barebones boilerplate code:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
Let's go line-by-line and explain what is being done in this short code snippet.
- After the import statements, we create an instance of the
FastAPI
class and assign it to the variableapp
. -
@app.get("/")
is a Python decorator that tells FastAPI to create an API endpoint via the HTTP GET method at the root URL/
. -
async def root()
defines an asynchronous function named root. We are using the async keyword here because FastAPI is built to work with asynchronous I/O operations. This means it can handle concurrent requests, which is better for performance. - In the body of the function, we return a Python dictionary which FastAPI helpfully converts to JSON for us. So, when the user goes to the root
/
endpoint, our API will automatically respond with a JSON object.
We can now run our project using the server package Uvicorn
(that we installed earlier) with the following command:
uvicorn main:app --reload
If we open our browser at http://127.0.0.1:8000
, we will just see the following plain JSON response:
{ "message": "Hello World" }
But if we add /docs
to the end of the URL, we can take advantage of FastAPI's in-built interactive API documentation capabilities.
The documentation UI in the screenshot below is provided by Swagger UI:
You can also try another documentation UI style that's automatically included with FastAPI.
Enter the URL http://127.0.0.1:8000/redoc
in your browser.
This one is provided by ReDoc:
Deploy on Render
This part assumes you have already created a repository for this project on GitHub. If you need instructions on how to do this, check out GitHub’s official docs.
One of Render’s advantages is that it provides an easy and intuitive way to connect to your GitHub repository.
First, go to render.com and create a new account with Render (you can use your GitHub credentials to speed things up).
Then click on the New button and select the option to create a new web service.
After linking your GitHub account, you should see the screen below, which provides a list of GitHub repos to connect to Render. Let's select our fastapi-render-appsignal example project.
This will then take us to the main configuration screen. Under region, simply select the region closest to your location (since I’m based in the UK, I will choose Frankfurt):
Further down the screen, we have a few more important options.
The build command will use the requirements.txt
file we created earlier in the project to install all the packages from our project on Render’s remote server.
Under start command, we will use Uvicorn again in our production environment and tell Render to start the application using main.py
in the root of our project.
Note: You must explicitly tell Render which host and port to use (unlike when using other servers like gunicorn). Unfortunately, this is not mentioned in any of the official Render documentation but I found the solution in the Render community forum and in the post 'Deploying FastAPI application to Render'.
Next, choose the free option under the list of instance types:
Lastly, under environment variables, specify the Python version as 3.10.7
. Ensure this matches the same version you are using in your local project.
With our web service configuration done, now we simply click the Create Web Service button and watch the project get deployed:
Remember, this will take a bit of time since we are using the free plan.
If everything goes smoothly at the end of the deployment process, we should see a final message in Render's logs saying: "Your service is live".
Now we can click on the public link Render has generated for us and see our Hello World FastAPI example, including the automatic documentation links at /docs
and /redoc
:
Installing the AppSignal Dashboard for FastAPI and Monitoring Deploys
It's great that we now have a basic FastAPI app running and deployed to Render, but what if something goes wrong? Even with the best manual and automated testing, the reality is that errors and bugs happen in software development. The key thing is to get alerted as soon as errors happen and to quickly identify where the problem is in the code.
In this section of the tutorial, we are going to specifically look at how to enable AppSignal to monitor your deployments. This part of the setup is crucial for you to see which errors are associated with a specific deployment. This will allow you to diagnose and fix problems in your app quickly and efficiently.
First, sign up for an AppSignal account (you can do a 30-day free trial, no credit card details required).
Next, add appsignal
and opentelemetry-instrumentation-fastapi
to your requirements.txt
file:
# requirements.txt
appsignal
opentelemetry-instrumentation-fastapi
Then run:
pip install -r requirements.txt
Now we need to create an appsignal.py
configuration file and add the following code:
import os
import subprocess
from appsignal import Appsignal
from dotenv import load_dotenv
load_dotenv()
revision = None
try:
revision = subprocess.check_output(
"git log --pretty=format:'%h' -n 1", shell=True
).strip()
except subprocess.CalledProcessError:
pass
appsignal = Appsignal(
active=True,
name="fastapi-render-appsignal",
push_api_key=os.getenv("APPSIGNAL_API_KEY"),
revision=revision,
)
In the code above, we initialize the Appsignal
object with a few different parameters, including:
- Setting
active
toTrue
to enable monitoring. - Providing the
name
for our application. - Putting the API key in an environment variable.
But the key parameter to enable deploy tracking is the revision
parameter. Inside the try-except
block (above the AppSignal initialization code), we fetch the latest commit hash so AppSignal can keep track of our deploys.
Lastly, we need to update main.py
to finish setting up AppSignal in our FastAPI app:
# main.py
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor #new
import appsignal #new
appsignal.start() #new
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
async def get_item(item_id: int):
return {"item_id": item_id}
FastAPIInstrumentor().instrument_app(app) #new
When we check out our AppSignal dashboard, the first thing we will see is the Getting Started screen which will provide some suggestions on additional configuration steps to complete:
But here we'll just focus on ensuring that AppSignal can track our deploys.
Go to the Organization page in the AppSignal dashboard and then click on Organization settings to activate AppSignal's integration with GitHub. Check out AppSignal's official docs on linking your repo for step-by-step instructions.
With the GitHub integration set up and your repo linked, all you need to do now is trigger a deployment in Render for AppSignal to start monitoring your deploys.
In our case, we simply need to push to our main branch:
git push origin main
If everything is set up correctly, we should see AppSignal tracking our deploys and any errors associated with each deploy commit hash in the Deploys section of the dashboard:
And that's it!
Wrapping Up
In this guide, we covered a lot of ground! First, we briefly introduced some of the advantages and disadvantages of choosing FastAPI and Render.
Then, we created a simple FastAPI app, deployed it to Render, and ended by monitoring those deploys with AppSignal.
Happy coding!
P.S. If you'd like to read Python posts as soon as they get off the press, subscribe to our Python Wizardry newsletter and never miss a single post!
Posted on July 10, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 28, 2024
November 13, 2024