Skip to content

Commit e58ab1b

Browse files
author
Andrew Brookins
committed
FastAPI integration example
1 parent 3f45793 commit e58ab1b

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

docs/fastapi_integration.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# FastAPI Integration
2+
3+
## Introduction
4+
5+
This section includes a complete example showing how to integrate Redis OM with FastAPI.
6+
7+
Good news: Redis OM was **specifically designed to integrate with FastAPI**!
8+
9+
## Concepts
10+
11+
### Every Redis OM Model is also a Pydantic model
12+
13+
Every Redis OM model is also a Pydantic model, so you can define a model and then pass the model class into any location that FastAPI expects a Pydantic model.
14+
15+
This means a couple of things:
16+
17+
1. A Redis OM model can be used for request body validation
18+
2. Redis OM models show up in the auto-generated API documentation
19+
20+
### Cache vs. Data
21+
22+
Redis works well as either a durable data store or a cache, but the optiomal Redis configuration is often different between these two use cases.
23+
24+
You almost always want to use a Redis instance tuned for caching when you're caching and a separate Redis instance tuned for data durability for storing application state.
25+
26+
This example shows how to manage these two uses of Redis within the same application. The app uses a FastAPI caching framework and dedicated caching instance of Redis for caching, and a separate Redis instance tuned for durability for Redis OM models.
27+
28+
29+
## Example app code
30+
31+
This is a complete example that you can run as-is:
32+
33+
```python
34+
import datetime
35+
from typing import Optional
36+
37+
import aioredis
38+
39+
from fastapi import FastAPI, HTTPException
40+
from starlette.requests import Request
41+
from starlette.responses import Response
42+
43+
from fastapi_cache import FastAPICache
44+
from fastapi_cache.backends.redis import RedisBackend
45+
from fastapi_cache.decorator import cache
46+
47+
from pydantic import EmailStr
48+
49+
from redis_om.model import HashModel, NotFoundError
50+
from redis_om.connections import get_redis_connection
51+
52+
# This Redis instance is tuned for durability.
53+
REDIS_DATA_URL = "redis://localhost:6380"
54+
55+
# This Redis instance is tuned for cache performance.
56+
REDIS_CACHE_URL = "redis://localhost:6381"
57+
58+
59+
class Customer(HashModel):
60+
first_name: str
61+
last_name: str
62+
email: EmailStr
63+
join_date: datetime.date
64+
age: int
65+
bio: Optional[str]
66+
67+
68+
app = FastAPI()
69+
70+
71+
@app.post("/customer")
72+
async def save_customer(customer: Customer):
73+
# We can save the model to Redis by calling `save()`:
74+
return customer.save()
75+
76+
77+
@app.get("/customers")
78+
async def list_customers(request: Request, response: Response):
79+
# To retrieve this customer with its primary key, we use `Customer.get()`:
80+
return {"customers": Customer.all_pks()}
81+
82+
83+
@app.get("/customer/{pk}")
84+
@cache(expire=10)
85+
async def get_customer(pk: str, request: Request, response: Response):
86+
# To retrieve this customer with its primary key, we use `Customer.get()`:
87+
try:
88+
return Customer.get(pk)
89+
except NotFoundError:
90+
raise HTTPException(status_code=404, detail="Customer not found")
91+
92+
93+
@app.on_event("startup")
94+
async def startup():
95+
r = aioredis.from_url(REDIS_CACHE_URL, encoding="utf8", decode_responses=True)
96+
FastAPICache.init(RedisBackend(r), prefix="fastapi-cache")
97+
98+
# You can set the Redis OM URL using the REDIS_OM_URL environment
99+
# variable, or by manually creating the connection using your model's
100+
# Meta object.
101+
Customer.Meta.database = get_redis_connection(url=REDIS_DATA_URL, decode_responses=True)
102+
```
103+
104+
## Testing the app
105+
106+
You should install the app's dependencies first. This app uses Poetry, so you'll want to make sure you have that installed first:
107+
108+
$ pip install poetry
109+
110+
Then install the dependencies:
111+
112+
$ poetry install
113+
114+
Next, start the server:
115+
116+
$ poetry run uvicorn --reload main:test
117+
118+
Then, in another shell, create a customer:
119+
120+
$ curl -X POST -H 'Content-Length: 0' "http://localhost:8000/customer"
121+
$ curl -X POST "http://localhost:8000/customer" -H 'Content-Type: application/json' -d '{"first_name":"Andrew","last_name":"Brookins","email":"[email protected]","age":"38","join_date":"2020
122+
-01-02"}'
123+
{"pk":"01FM2G8EP38AVMH7PMTAJ123TA","first_name":"Andrew","last_name":"Brookins","email":"[email protected]","join_date":"2020-01-02","age":38,"bio":""}
124+
125+
Get a copy of the value for "pk" and make another request to get that customer:
126+
127+
$ curl "http://localhost:8000/customer/01FM2G8EP38AVMH7PMTAJ123TA"
128+
{"pk":"01FM2G8EP38AVMH7PMTAJ123TA","first_name":"Andrew","last_name":"Brookins","email":"[email protected]","join_date":"2020-01-02","age":38,"bio":""}
129+
130+
You can also get a list of all customer PKs:
131+
132+
$ curl "http://localhost:8000/customers"
133+
{"customers":["01FM2G8EP38AVMH7PMTAJ123TA"]}

0 commit comments

Comments
 (0)