FastAPI is a powerful web framework for building APIs with Python that is known for its speed, performance, and ease of use. In this tutorial, we will discuss 4 tips for building a production-ready FastAPI backend that is scalable, resilient, and efficient.
- Use Dependency Injection for Dependencies:
One of the core features of FastAPI is its support for dependency injection, which allows you to cleanly separate your application logic from its external dependencies. By using dependency injection, you can easily swap out components, mock dependencies for testing, and improve the maintainability of your codebase.
To use dependency injection in FastAPI, you can define dependencies using the Depends
class and pass them into your route functions as arguments. For example, you can define a dependency for a database connection like this:
from fastapi import Depends, FastAPI
app = FastAPI()
def get_db():
db = DBConnection()
try:
yield db
finally:
db.close()
@app.get("/")
def get_data(db: DBConnection = Depends(get_db)):
# Use the db connection to retrieve data
data = db.get_data()
return data
In this example, the get_db
function creates a new DBConnection
object and yields it as a dependency for the get_data
route function. This allows you to easily inject the database connection into your route function without cluttering your code with manual instantiation and management of dependencies.
- Use Background Tasks for Asynchronous Operations:
FastAPI supports running background tasks asynchronously to improve the performance of your backend code. By using background tasks, you can offload time-consuming operations such as data processing, notifications, or resource cleanup to separate worker processes, allowing your main application to continue handling incoming requests without delay.
To define a background task in FastAPI, you can use the background_tasks
parameter in your route function and enqueue tasks using its add_task
method. For example, you can define a background task to send an email like this:
from fastapi import BackgroundTasks, FastAPI
app = FastAPI()
def send_email(email: str, message: str):
# Send an email to the specified address with the given message
pass
@app.post("/send_email")
def send_email_view(email: str, message: str, background_tasks: BackgroundTasks):
background_tasks.add_task(send_email, email, message)
return {"message": "Email queued for sending"}
In this example, the send_email_view
route function enqueues a background task to send an email with the specified address and message. The task will be executed asynchronously by FastAPI’s internal task manager, allowing the main application to respond to the client quickly.
- Use Caching for Performance Optimization:
To improve the performance of your FastAPI backend, consider implementing caching for frequently accessed data or expensive computations. By caching results in memory or a shared cache server, you can reduce the workload on your database and speed up response times for repeated requests.
FastAPI provides built-in support for caching using tools such as cachetools
or aiocache
, which allow you to easily cache function results or HTTP responses. For example, you can cache the results of a computationally expensive function like this:
from fastapi import FastAPI
from cachetools import cached, TTLCache
app = FastAPI()
cache = TTLCache(maxsize=100, ttl=300)
@cached(cache)
def expensive_function(arg):
# Perform a time-consuming computation
return result
@app.get("/compute/{arg}")
def compute_view(arg: int):
result = expensive_function(arg)
return {"result": result}
In this example, the expensive_function
is cached using a TTLCache
with a maximum size of 100 entries and a time-to-live of 300 seconds. The cached results are stored in memory and will be used for subsequent requests with the same argument, avoiding redundant computations and improving performance.
- Implement Rate Limiting for Security and Stability:
To protect your FastAPI backend from abuse, denial-of-service attacks, or excessive resource consumption, consider implementing rate limiting to restrict the number of requests a client can make within a specified time frame. By enforcing rate limits, you can prevent malicious or malfunctioning clients from overwhelming your server and ensure fair access for all users.
FastAPI offers several rate limiting solutions, including middleware plugins like starlette-rate-limit
or external services like Redis or Memcached. You can configure rate limits based on IP address, user authentication, or custom headers to control the traffic flow to your API endpoints.
For example, you can enforce a rate limit of 100 requests per minute for a specific route using the RateLimiter
middleware like this:
from fastapi import FastAPI
from starlette.middleware import Middleware
from starlette.middleware.ratelimit import RateLimiter
app = FastAPI()
app.add_middleware(RateLimiter, max_requests=100, period=60)
@app.get("/")
def index():
return {"message": "Hello, World!"}
In this example, the RateLimiter
middleware is added to the FastAPI application with a maximum of 100 requests per minute for all routes. Any client exceeding this limit will receive a HTTP 429 Too Many Requests response, indicating that the rate limit has been exceeded.
By following these tips for building a production-ready FastAPI backend, you can ensure the scalability, performance, and security of your API while delivering a reliable and responsive experience for your users. Experiment with these techniques in your projects and continue exploring the capabilities of FastAPI to create robust and efficient web applications.
Get started with Pulumi: https://www.pulumi.com/?utm_source=arjancodes
I wonder, at 10:10 would it be possible to use a context manager instead? Something like "with session_local() as db: yield db
Just curious, I'm learning loads from your videos!
Why not terraform?
Good on pulumi to sponsor this video. Just recently stumbled on this channel and it’s really good. I’ll definitely be giving a pulumi a try very soon
This was great! Thanks!
The FastAPI videos are awesome! One thing I haven't found much at all about and I find myself frustrated with a lot is setting up FastAPI with SQLModel using more complex databases with many-to-many relationships and properly using TYPE_CHECKING and other things to avoid circular imports when breaking the application into separate components. A video covering this would be GREATLY appreciated! Thanks again for all the work you do!
i use sqlalchemy should i use every code in try catch to handle error most of error i return responce like i get error like datebase is down or should i handle global error
I would highly appreciate if you will make video about nice way to implement auth in Fast API.
They have so poor way to manage role based authorization, I was shocked after .Net.
Like forget about attributes or other handy stuff, use dependency injection instead! That's sick. I thought Python is kind of modern cool language and has all topics covered in a stylish manner 😁
Thank you, Arjan, for this very informative video! I have a question. You have moved operations out of the endpoint functions and put them in model files, just below existing models as methods. In my case, I have created files containing utils classes containing static methods that can be called inside endpoint functions. Is that a bad practice?
Hi Arjan, do you provide consulting services?
I am solo developer for a small company, and I use FastAPI for the backend. Some best practices to streamline development would come in very handy.
Thanks
thank you sir, it was very helpful.
🙂 From a very old school programmer from the dark ages on IBM mainframe between web/all types of terminals, etc
If you want to use high speed volume computer background things like Rusk/etc. that deal with terminals/and/or HTML
then
Python is ok, but also consider Java running as the HTML and terminal handler relative to the internet to talk to things like RUST/etc.
Let Java talk to the background RUST/C/etc. The Java classes are good performers and allow the heavy lifters to focus on the
basic high performance data sources and databases, etc. to ignore all the web/etc. display/input nonsense, html, etc.
This is very useful. I am trying to figure out how to use sqlmodel and fastapi together in the neatest possible way. One thing I find weird is creating multiple classes for what seems like the same thing. For example, a pydantic base model plus a sqlmodel. And then separate classes for the CRUD functionality. I see people do this in different way, and would like to know if there is a "correct" way of doing it.
I would love to see the production setup for FastAPI project using Docker on Virtual Machine. I mean the production Dockerfile, docker-compose. The production FastAPI code no super example, but real good example. Listed things what to do on the docker side to secure, develop FastAPI project. Listed things to do on VM how to secure your app. From ground up. Does your course cover that ? ❤
10:15 what do you think about using with statement in get_db() instead generator?
havnt watched in a while because of those toxic ai hype videos. Feels like the quality degraded a lot and just made to pump out a sponsored video. tip 1 & 2 basically useless. Anyone who would write a single file complex api should probably not be allowed to do so in the first place. Tip 3 is sponsorship placement. Tip 4 also useless, auth is not a "tip", its a neccessity for a produciton api. How can this be a 27 minute video, like for real?
learning fastapi and this was very helpful. just curious what font style are you using for the file explorer and the editor?
Authentication/authorisation would be very nice
Some time ago you did perfect video about 'routing testing' but in this video you add 'rate limitation'.
How should we test 'rate limitation'?
I also vote for video about OAuth.
painless writing!