pypi-fastapi

Description
FastAPI framework, high performance, easy to learn, fast to code, ready for production
Author
tessl
Last updated

How to use

npx @tessl/cli registry install tessl/pypi-fastapi@0.116.0

data-utilities.md docs/

1
# Data Utilities
2
3
FastAPI provides utility functions for data encoding and serialization, particularly useful for converting Python objects to JSON-compatible formats. These utilities are essential for handling complex data types that aren't natively JSON serializable, such as datetime objects, Pydantic models, and database models.
4
5
## Capabilities
6
7
### JSON Encodable Converter
8
9
Primary utility function for converting Python objects to JSON-compatible formats with extensive customization options.
10
11
```python { .api }
12
def jsonable_encoder(
13
obj: Any,
14
include: Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]] = None,
15
exclude: Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]] = None,
16
by_alias: bool = True,
17
exclude_unset: bool = False,
18
exclude_defaults: bool = False,
19
exclude_none: bool = False,
20
round_trip: bool = True,
21
timedelta_isoformat: str = "iso8601",
22
sqlalchemy_safe: bool = True,
23
fallback: Callable[[Any], Any] = None,
24
) -> Any:
25
"""
26
Convert any object to a JSON-compatible format.
27
28
Parameters:
29
- obj: The object to encode
30
- include: Fields to include (set of field names or dict with nested structure)
31
- exclude: Fields to exclude (set of field names or dict with nested structure)
32
- by_alias: Use field aliases if available (Pydantic models)
33
- exclude_unset: Exclude fields that weren't explicitly set
34
- exclude_defaults: Exclude fields that contain their default value
35
- exclude_none: Exclude fields with None values
36
- round_trip: Enable round-trip serialization compatibility
37
- timedelta_isoformat: Format for timedelta objects ("iso8601" or "float")
38
- sqlalchemy_safe: Safe handling of SQLAlchemy models
39
- fallback: Custom fallback function for unsupported types
40
41
Returns:
42
JSON-compatible object (dict, list, str, int, float, bool, None)
43
"""
44
```
45
46
## Usage Examples
47
48
### Basic Object Encoding
49
50
```python
51
from fastapi.encoders import jsonable_encoder
52
from datetime import datetime, date, timedelta
53
from decimal import Decimal
54
from uuid import UUID, uuid4
55
56
# Basic Python types
57
data = {
58
"string": "hello",
59
"integer": 42,
60
"float": 3.14,
61
"boolean": True,
62
"none": None,
63
"list": [1, 2, 3],
64
"dict": {"nested": "value"}
65
}
66
67
encoded = jsonable_encoder(data)
68
print(encoded) # Already JSON-compatible, returned as-is
69
70
# Complex types that need encoding
71
complex_data = {
72
"datetime": datetime.now(),
73
"date": date.today(),
74
"timedelta": timedelta(hours=2, minutes=30),
75
"decimal": Decimal("10.50"),
76
"uuid": uuid4(),
77
"bytes": b"binary data",
78
"set": {1, 2, 3}
79
}
80
81
encoded_complex = jsonable_encoder(complex_data)
82
print(encoded_complex)
83
# {
84
# "datetime": "2024-01-15T10:30:00.123456",
85
# "date": "2024-01-15",
86
# "timedelta": "PT2H30M",
87
# "decimal": 10.5,
88
# "uuid": "123e4567-e89b-12d3-a456-426614174000",
89
# "bytes": "YmluYXJ5IGRhdGE=", # base64 encoded
90
# "set": [1, 2, 3]
91
# }
92
```
93
94
### Pydantic Model Encoding
95
96
```python
97
from fastapi.encoders import jsonable_encoder
98
from pydantic import BaseModel, Field
99
from typing import Optional
100
from datetime import datetime
101
102
class User(BaseModel):
103
id: int
104
name: str
105
email: str
106
full_name: Optional[str] = Field(None, alias="fullName")
107
created_at: datetime
108
is_active: bool = True
109
110
class UserProfile(BaseModel):
111
user: User
112
preferences: dict
113
login_count: int = 0
114
115
# Create model instances
116
user = User(
117
id=1,
118
name="john_doe",
119
email="john@example.com",
120
fullName="John Doe",
121
created_at=datetime.now()
122
)
123
124
profile = UserProfile(
125
user=user,
126
preferences={"theme": "dark", "notifications": True}
127
)
128
129
# Encode with default settings
130
encoded = jsonable_encoder(profile)
131
print(encoded)
132
133
# Encode using aliases
134
encoded_with_aliases = jsonable_encoder(profile, by_alias=True)
135
print(encoded_with_aliases["user"]["fullName"]) # Uses alias
136
137
# Exclude certain fields
138
encoded_minimal = jsonable_encoder(
139
profile,
140
exclude={"user": {"created_at"}, "login_count"}
141
)
142
143
# Include only specific fields
144
encoded_specific = jsonable_encoder(
145
profile,
146
include={"user": {"id", "name"}, "preferences"}
147
)
148
149
# Exclude unset fields
150
user_partial = User(id=2, name="jane", email="jane@example.com")
151
encoded_no_unset = jsonable_encoder(user_partial, exclude_unset=True)
152
# Won't include created_at if it wasn't explicitly set
153
154
# Exclude None values
155
user_with_none = User(
156
id=3,
157
name="bob",
158
email="bob@example.com",
159
full_name=None, # Explicitly set to None
160
created_at=datetime.now()
161
)
162
encoded_no_none = jsonable_encoder(user_with_none, exclude_none=True)
163
```
164
165
### Database Model Integration
166
167
```python
168
from fastapi import FastAPI, Depends
169
from fastapi.encoders import jsonable_encoder
170
from sqlalchemy.orm import Session
171
# Assuming SQLAlchemy models
172
173
app = FastAPI()
174
175
@app.get("/users/{user_id}")
176
def get_user(user_id: int, db: Session = Depends(get_db)):
177
user = db.query(UserModel).filter(UserModel.id == user_id).first()
178
179
if not user:
180
raise HTTPException(status_code=404, detail="User not found")
181
182
# Convert SQLAlchemy model to JSON-compatible dict
183
user_data = jsonable_encoder(user, sqlalchemy_safe=True)
184
return user_data
185
186
@app.get("/users/{user_id}/profile")
187
def get_user_profile(user_id: int, db: Session = Depends(get_db)):
188
user = db.query(UserModel).filter(UserModel.id == user_id).first()
189
190
if not user:
191
raise HTTPException(status_code=404, detail="User not found")
192
193
# Include related data, exclude sensitive fields
194
profile_data = jsonable_encoder(
195
user,
196
include={
197
"id", "name", "email", "created_at", "last_login",
198
"profile": {"bio", "location", "website"},
199
"posts": {"id", "title", "created_at"}
200
},
201
exclude={"password_hash", "email_verified_token"}
202
)
203
return profile_data
204
```
205
206
### Custom Fallback Function
207
208
```python
209
from fastapi.encoders import jsonable_encoder
210
import numpy as np
211
from typing import Any
212
213
# Custom fallback for handling NumPy arrays
214
def numpy_fallback(obj: Any) -> Any:
215
if isinstance(obj, np.ndarray):
216
return obj.tolist()
217
elif isinstance(obj, np.integer):
218
return int(obj)
219
elif isinstance(obj, np.floating):
220
return float(obj)
221
else:
222
# Re-raise the TypeError to use default handling
223
raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
224
225
# Data with NumPy objects
226
data_with_numpy = {
227
"array": np.array([1, 2, 3, 4]),
228
"matrix": np.array([[1, 2], [3, 4]]),
229
"int64": np.int64(42),
230
"float64": np.float64(3.14159)
231
}
232
233
encoded_numpy = jsonable_encoder(data_with_numpy, fallback=numpy_fallback)
234
print(encoded_numpy)
235
# {
236
# "array": [1, 2, 3, 4],
237
# "matrix": [[1, 2], [3, 4]],
238
# "int64": 42,
239
# "float64": 3.14159
240
# }
241
```
242
243
### Response Encoding in Endpoints
244
245
```python
246
from fastapi import FastAPI, HTTPException
247
from fastapi.encoders import jsonable_encoder
248
from fastapi.responses import JSONResponse
249
250
app = FastAPI()
251
252
@app.get("/complex-data")
253
def get_complex_data():
254
complex_response = {
255
"timestamp": datetime.now(),
256
"data": {
257
"measurements": [
258
{"value": Decimal("123.456"), "unit": "kg"},
259
{"value": Decimal("789.012"), "unit": "kg"}
260
],
261
"metadata": {
262
"id": uuid4(),
263
"processed": True
264
}
265
}
266
}
267
268
# Encode the complex data structure
269
encoded_response = jsonable_encoder(complex_response)
270
return JSONResponse(content=encoded_response)
271
272
@app.post("/process-data")
273
def process_data(raw_data: dict):
274
# Process and potentially modify data
275
processed = {
276
"original": raw_data,
277
"processed_at": datetime.now(),
278
"result": calculate_result(raw_data),
279
"metadata": {
280
"version": "1.0",
281
"processor_id": uuid4()
282
}
283
}
284
285
# Use jsonable_encoder to ensure everything is JSON-compatible
286
return jsonable_encoder(processed, exclude_none=True)
287
```
288
289
### Time Delta Formatting Options
290
291
```python
292
from fastapi.encoders import jsonable_encoder
293
from datetime import timedelta
294
295
duration_data = {
296
"short": timedelta(minutes=30),
297
"medium": timedelta(hours=2, minutes=45),
298
"long": timedelta(days=5, hours=3, minutes=20)
299
}
300
301
# ISO 8601 format (default)
302
iso_encoded = jsonable_encoder(duration_data, timedelta_isoformat="iso8601")
303
print(iso_encoded)
304
# {
305
# "short": "PT30M",
306
# "medium": "PT2H45M",
307
# "long": "P5DT3H20M"
308
# }
309
310
# Float format (total seconds)
311
float_encoded = jsonable_encoder(duration_data, timedelta_isoformat="float")
312
print(float_encoded)
313
# {
314
# "short": 1800.0,
315
# "medium": 9900.0,
316
# "long": 443400.0
317
# }
318
```
319
320
## Types
321
322
```python { .api }
323
from typing import Any, Callable, Dict, List, Optional, Set, Union
324
325
# Include/exclude type for field selection
326
IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any], None]
327
328
# Fallback function type
329
FallbackFunc = Callable[[Any], Any]
330
331
# Supported timedelta formats
332
TimedeltaIsoFormat = Union["iso8601", "float"]
333
```