Skip to main content

FastAPI route for efficient caching.

Project description

FastAPI Caching Route

PR Checks Coverage Coverage Status Docs PyPI

FastAPI route class for response caching before entering the endpoint handler.

fastapi-caching-route plugs into fastapi.APIRouter, stores complete response payloads in an aiocache backend, and serves cache hits directly from the route handler. It is useful for expensive read endpoints where the cache key can be derived from the request path, query parameters, or a custom key builder.

⚠️ This project is a proof of concept and is not yet recommended for production use!

Features

  • Cache regular FastAPI responses and StreamingResponse bodies.
  • Return X-Cache: MISS for stored responses and X-Cache: HIT for cache hits.
  • Generate ETag headers for cached responses.
  • Return 304 Not Modified for matching If-None-Match requests.
  • Build default cache keys from the route path and declared query parameters.
  • Provide custom key builders for path parameters or application-specific keys.
  • Include selected request headers in default cache keys for negotiated responses.
  • Run explicitly configured dependencies before cache lookup, for example API key checks.
  • Pass namespace and ttl through to the underlying aiocache backend.
  • Manually invalidate cached values through FastAPICache.invalidate_cached().

Installation

uv add fastapi-caching-route
pip install fastapi-caching-route

Install FastAPI and a cache backend that matches your application. For local development or tests, aiocache.SimpleMemoryCache is enough:

uv add fastapi aiocache
pip install fastapi aiocache

Basic Usage

Use CachingRoute as the router route class and decorate endpoints with FastAPICache.

from aiocache import SimpleMemoryCache
from fastapi import APIRouter, FastAPI
from fastapi_caching_route import CachingRoute, FastAPICache


router = APIRouter(route_class=CachingRoute)
cache = FastAPICache(SimpleMemoryCache())


@cache()
@router.get('/')
def cached() -> str:
    return 'Hello, World!'


app = FastAPI()
app.include_router(router)

Start an app with this route and call it twice. The first response is produced by the endpoint and stored in the cache:

X-Cache: MISS

The second response is returned from the cache before the endpoint handler is called:

X-Cache: HIT

Routes decorated with @cache() must be registered on a router that uses CachingRoute. A plain APIRoute ignores the cache configuration.

Cache Keys

By default, the cache key is built from the request path and declared query parameters. Query parameter order is normalized, so these two requests hit the same cache entry when the endpoint declares a and b:

/query?a=a&b=b
/query?b=b&a=a

Use a custom key builder when the cache key should be based on path parameters, headers, user context, or another application-specific value.

from fastapi import Request


def user_key_builder(request: Request) -> str:
    user_id = request.scope['path_params']['user_id']
    return f'user:{user_id}'


@cache(key_builder=user_key_builder, ttl=60, namespace='users')
@router.get('/users/{user_id}')
def get_user(user_id: int) -> dict[str, int]:
    return {'id': user_id}

ttl and namespace are passed to aiocache. When the underlying cache instance also has a namespace, FastAPICache concatenates the root and endpoint namespace by default:

cache = FastAPICache(RedisCache(namespace='api'))


@cache(namespace='users')
@router.get('/users/{user_id}')
def get_user(user_id: int): ...


# Resulting namespace: "api:users"

Pass namespace_policy="replace" to FastAPICache if endpoint namespaces should replace the root namespace instead.

If the response representation depends on request headers, include those headers in the default cache key with vary_headers. The route also returns a matching Vary header:

@cache(vary_headers=['Accept-Language'])
@router.get('/localized')
def localized(request: Request) -> str:
    return request.headers.get('accept-language', 'en')

Responses with Vary: * are not cached.

Dependencies Before Cache Lookup

FastAPI dependencies on the route still run on cache misses. If a dependency must also be resolved before cache lookup, pass it to @cache(dependencies=...). This is mainly useful for security dependencies that should reject unauthorized requests before a cached response can be served.

from fastapi import Depends
from fastapi.security import APIKeyHeader


api_key = Depends(APIKeyHeader(name='X-Key'))


@cache(dependencies=[api_key])
@router.get('/private', dependencies=[api_key])
def private_data() -> str:
    return 'secret'

Keep the dependency on the route as well if it must be enforced for cache misses.

Conditional Requests

Cached responses without an existing ETag get one based on the response body. If the endpoint already sets ETag, that value is preserved. On a cache hit, requests with a matching If-None-Match header return 304 Not Modified with an empty body. If-None-Match supports weak tags, tag lists, and *.

curl http://127.0.0.1:8000/cached -H 'If-None-Match: "..."'

Invalidation

Use the same key builder logic when invalidating cache entries after writes.

from fastapi import Request


def user_cache_key(user_id: int) -> str:
    return f'user:{user_id}'


def user_key_builder(request: Request) -> str:
    return user_cache_key(request.scope['path_params']['user_id'])


@cache(key_builder=user_key_builder)
@router.get('/users/{user_id}')
def get_user(user_id: int): ...


@router.patch('/users/{user_id}')
async def update_user(user_id: int) -> dict[str, int]:
    await cache.invalidate_cached(user_cache_key(user_id))
    return {'id': user_id}

invalidate_cached() returns the number of deleted keys reported by the underlying cache backend.

Examples

The repository contains runnable examples:

  • examples/simple.py: minimal cached route.
  • examples/complex.py: cache hits and misses, auth dependency, ETag handling, streaming response caching, query parameter keys, and non-cacheable responses.
  • examples/invalidate.py: custom key builder and manual invalidation after an update.

Follow the detailed walkthrough in the examples README.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_caching_route-0.6.0.tar.gz (108.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_caching_route-0.6.0-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_caching_route-0.6.0.tar.gz.

File metadata

  • Download URL: fastapi_caching_route-0.6.0.tar.gz
  • Upload date:
  • Size: 108.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastapi_caching_route-0.6.0.tar.gz
Algorithm Hash digest
SHA256 94324d165b205481be91967389bc0e939bf6336a64fc934c28701e5e9bd0a377
MD5 83f18b1dcb148be6691d204f927651d2
BLAKE2b-256 313074bffbaef36a1605143dc79ab2e39a9867e9d79982827193e5acf1450afe

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_caching_route-0.6.0.tar.gz:

Publisher: deploy-pypi.yaml on AgroDT/fastapi-caching-route

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastapi_caching_route-0.6.0-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_caching_route-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7154e05a794c999a4276913f117d7e63c3232e59a5f9f075603c735b2e4a311e
MD5 87fbb7182a9c3ef7063a351e47f9456f
BLAKE2b-256 5d75e07cf25e92fc2c982a70dd55a8991449ace5ea91db44b6590fbe89155c96

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_caching_route-0.6.0-py3-none-any.whl:

Publisher: deploy-pypi.yaml on AgroDT/fastapi-caching-route

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page