Redis 中文文档 Redis 中文文档
指南
redis.io (opens new window)
指南
redis.io (opens new window)
  • 关于
    • Redis 开源治理
    • Redis 发布周期
    • Redis 赞助商
  • 入门
  • 数据类型
  • Redis Stack
  • 命令
  • 手册

fastapi-cache


CI/CD

Introduction


fastapi-cache is a tool to cache FastAPI endpoint and function results, with backends supporting Redis, Memcached, and Amazon DynamoDB.

Features


Supports redis, memcache, dynamodb, and in-memory backends.
Easy integration with FastAPI.
Support for HTTP cache headers like ETag and Cache-Control, as well as conditional If-Match-None requests.

Requirements


FastAPI
redis when using RedisBackend.
memcache when using MemcacheBackend.
aiobotocore when using DynamoBackend.

Install


  1. ``` shell
  2. > pip install fastapi-cache2
  3. ```

or

  1. ``` shell
  2. > pip install "fastapi-cache2[redis]"
  3. ```

or

  1. ``` shell
  2. > pip install "fastapi-cache2[memcache]"
  3. ```

or

  1. ``` shell
  2. > pip install "fastapi-cache2[dynamodb]"
  3. ```

Usage


Quick Start


  1. ``` python
  2. from fastapi import FastAPI
  3. from starlette.requests import Request
  4. from starlette.responses import Response

  5. from fastapi_cache import FastAPICache
  6. from fastapi_cache.backends.redis import RedisBackend
  7. from fastapi_cache.decorator import cache

  8. from redis import asyncio as aioredis

  9. app = FastAPI()

  10. @cache()
  11. async def get_cache():
  12.     return 1

  13. @app.get("/")
  14. @cache(expire=60)
  15. async def index():
  16.     return dict(hello="world")

  17. @app.on_event("startup")
  18. async def startup():
  19.     redis = aioredis.from_url("redis://localhost")
  20.     FastAPICache.init(RedisBackend(redis), prefix="fastapi-cache")
  21. ```

Initialization


First you must call FastAPICache.init during startup FastAPI startup; this is where you set global configuration.

Use the @cache decorator


If you want cache a FastAPI response transparently, you can use the @cache decorator between the router decorator and the view function.

Parameter type default description
:--- :--- :--- :---
expire int sets the caching time in seconds
namespace str "" namespace to use to store certain cache items
coder Coder JsonCoder which coder to use, e.g. JsonCoder
key_builder KeyBuilder callable default_key_builder which key builder to use
injected_dependency_namespace str __fastapi_cache prefix for injected dependency keywords.
cache_status_header str X-FastAPI-Cache Name for the header on the response indicating if the request was served from cache; either HIT or MISS.

You can also use the @cache decorator on regular functions to cache their result.

Injected Request and Response dependencies


The cache decorator injects dependencies for the Request and Response objects, so that it can add cache control headers to the outgoing response, and return a 304 Not Modified response when the incoming request has a matching If-Non-Match header. This only happens if the decorated endpoint doesn't already list these dependencies already.

The keyword arguments for these extra dependencies are named __fastapi_cache_request and __fastapi_cache_response to minimize collisions. Use the injected_dependency_namespace argument to @cache to change the prefix used if those names would clash anyway.

Supported data types


When using the (default) JsonCoder, the cache can store any data type that FastAPI can convert to JSON, including Pydantic models and dataclasses, providedthat your endpoint has a correct return type annotation. An annotation is not needed if the return type is a standard JSON-supported Python type such as a dictionary or a list.

E.g. for an endpoint that returns a Pydantic model named SomeModel, the return annotation is used to ensure that the cached result is converted back to the correct class:

  1. ``` python
  2. from .models import SomeModel, create_some_model

  3. @app.get("/foo")
  4. @cache(expire=60)
  5. async def foo() -> SomeModel:
  6.     return create_some_model
  7. ```

It is not sufficient to configure a response model in the route decorator; the cache needs to know what the method itself returns. If no return type decorator is given, the primitive JSON type is returned instead.

For broader type support, use the fastapi_cache.coder.PickleCoder or implement a custom coder (see below).

Custom coder


By default use JsonCoder, you can write custom coder to encode and decode cache result, just need inherit fastapi_cache.coder.Coder.

  1. ``` python
  2. from typing import Any
  3. import orjson
  4. from fastapi.encoders import jsonable_encoder
  5. from fastapi_cache import Coder

  6. class ORJsonCoder(Coder):
  7.     @classmethod
  8.     def encode(cls, value: Any) -> bytes:
  9.         return orjson.dumps(
  10.             value,
  11.             default=jsonable_encoder,
  12.             option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY,
  13.         )

  14.     @classmethod
  15.     def decode(cls, value: bytes) -> Any:
  16.         return orjson.loads(value)

  17. @app.get("/")
  18. @cache(expire=60, coder=ORJsonCoder)
  19. async def index():
  20.     return dict(hello="world")
  21. ```

Custom key builder


By default the default_key_builder builtin key builder is used; this creates a cache key from the function module and name, and the positional and keyword arguments converted to their repr() representations, encoded as a MD5 hash. You can provide your own by passing a key builder in to @cache(), or to FastAPICache.init() to apply globally.

For example, if you wanted to use the request method, URL and query string as a cache key instead of the function identifier you could use:

  1. ``` python
  2. def request_key_builder(
  3.     func,
  4.     namespace: str = "",
  5.     *,
  6.     request: Request = None,
  7.     response: Response = None,
  8.     *args,
  9.     **kwargs,
  10. ):
  11.     return ":".join([
  12.         namespace,
  13.         request.method.lower(),
  14.         request.url.path,
  15.         repr(sorted(request.query_params.items()))
  16.     ])

  17. @app.get("/")
  18. @cache(expire=60, key_builder=request_key_builder)
  19. async def index():
  20.     return dict(hello="world")
  21. ```

Backend notes


InMemoryBackend


The InMemoryBackend stores cache data in memory and only deletes when an expired key is accessed. This means that if you don't access a function after data has been cached, the data will not be removed automatically.

RedisBackend


When using the Redis backend, please make sure you pass in a redis client that does not decode responses (decode_responses mustbe False, which is the default). Cached data is stored as bytes (binary), decoding these in the Redis client would break caching.

Tests and coverage


  1. ``` shell
  2. coverage run -m pytest
  3. coverage html
  4. xdg-open htmlcov/index.html
  5. ```

License


This project is licensed under the Apache-2.0 License.
Last Updated: 2023-09-03 19:17:54