Skip to main content

FastAPI-Cache using Redis

You can use the FastAPI-Cache library with a FastAPI app deployed on Sevalla by connecting a Redis service to your application.

Install

To use the caching extension, both FastAPI-Cache and Redis need to be installed.
pip install fastapi-cache2 redis
pip freeze > requirements.txt

Code

The library must first be set up as a lifespan function to work with FastAPI. This setup can be added in main.py.
# app/main.py
from collections.abc import AsyncIterator 
from contextlib import asynccontextmanager
from fastapi_cache import FastAPICache
from fastapi_cache.backends.redis import RedisBackend
from redis import asyncio as aioredis
from fastapi import FastAPI
from app.core.config import settings

@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
    redis = aioredis.from_url(settings.REDIS_URL)
    FastAPICache.init(RedisBackend(redis), prefix="fastapi-cache")
    yield

app = FastAPI() 
app = FastAPI(lifespan=lifespan) 
You then need to add REDIS_URL to config.py.
# app/core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env",)

    SQLALCHEMY_DATABASE_URI: str = ""
    REDIS_URL: str = ""

settings = Settings()
If you want to use caching in your local environment, then add REDIS_URL to your .env file.
# .env
SQLALCHEMY_DATABASE_URI=sqlite:///db.sqlite3
REDIS_URL=redis://localhost:6379/0
Within Sevalla, you can create a Redis database and connect it to your app. Make sure you add the REDIS_URL to your app when you connect the Redis service to it.

Example

To cache a route, decorate the route with @cache decorator. This example caches the route for two minutes.
# app/main.py
...
from fastapi import FastAPI 
from fastapi import FastAPI, Response 
from app.core.config import settings
from fastapi_cache.decorator import cache 
from datetime import datetime
...
app = FastAPI(lifespan=lifespan)

@app.get("/cached") 
@cache(expire=120)
def index(response: Response):
    return {"message": f"Last generated at {datetime.now()}"}
Navigate to the cached/ endpoint, the time the view was added to the cache will be displayed until the cache is updated. FastAPI-Cache can also be used with the same configuration to cache regular functions in your app. If you want to cache your entire API, consider using edge caching instead.

CDN

Even though static files aren’t typically served from FastAPI, if you happen to serve static files, you can take advantage of CDN caching. To add CDN caching, enable the CDN setting to cache your static assets on Cloudflare. To verify your static files are being cached correctly, request a file and inspect the response headers. The cf-cache-status header should be either HIT or MISS. MISS should only occur when the file needs to be set or updated in the CDN. HIT will be the expected value for most requests.

Edge caching

If your app primarily serves endpoints with data that doesn’t change frequently, you can use edge caching to cache the responses. This will apply to your entire app, except for endpoints that explicitly include headers preventing caching, which the edge cache will ignore. You can prevent caching by updating the endpoint’s response to have a Cache-Control header with the value no-store.
# main.py
from fastapi import FastAPI, Response
from app.core.config import settings
from datetime import datetime

app = FastAPI()

@app.get("/")
def index(response: Response):
    response.headers["Cache-Control"] = "no-store"
    return {"message": f"The current time is {datetime.now()}"}
To control how long a page will remain in the cache, you need to set the max-age value in your Cache-Control header.
# main.py
from fastapi import FastAPI, Response
from app.core.config import settings
from datetime import datetime

app = FastAPI()

@app.get("/")
def index(response: Response):
    response.headers["Cache-Control"] = "no-store"
    return {"message": f"The current time is {datetime.now()}"}

@app.get("/page") 
def page(response: Response):
    response.headers["Cache-Control"] = "max-age=120"
    return {"message": f"The current time is {datetime.now()}"}
To verify your endpoints are being cached correctly, request an endpoint and inspect the response headers. The cf-cache-status header should be either HIT or MISS. MISS should only occur when the page needs to be set or updated in the CDN. HIT will be the expected value for most requests.