- Spec files
pypi-fastapi
Describes: pkg:pypi/fastapi@0.116.x
- Description
- FastAPI framework, high performance, easy to learn, fast to code, ready for production
- Author
- tessl
- Last updated
data-utilities.md docs/
1# Data Utilities23FastAPI 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.45## Capabilities67### JSON Encodable Converter89Primary utility function for converting Python objects to JSON-compatible formats with extensive customization options.1011```python { .api }12def jsonable_encoder(13obj: Any,14include: Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]] = None,15exclude: Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]] = None,16by_alias: bool = True,17exclude_unset: bool = False,18exclude_defaults: bool = False,19exclude_none: bool = False,20round_trip: bool = True,21timedelta_isoformat: str = "iso8601",22sqlalchemy_safe: bool = True,23fallback: Callable[[Any], Any] = None,24) -> Any:25"""26Convert any object to a JSON-compatible format.2728Parameters:29- obj: The object to encode30- 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 set34- exclude_defaults: Exclude fields that contain their default value35- exclude_none: Exclude fields with None values36- round_trip: Enable round-trip serialization compatibility37- timedelta_isoformat: Format for timedelta objects ("iso8601" or "float")38- sqlalchemy_safe: Safe handling of SQLAlchemy models39- fallback: Custom fallback function for unsupported types4041Returns:42JSON-compatible object (dict, list, str, int, float, bool, None)43"""44```4546## Usage Examples4748### Basic Object Encoding4950```python51from fastapi.encoders import jsonable_encoder52from datetime import datetime, date, timedelta53from decimal import Decimal54from uuid import UUID, uuid45556# Basic Python types57data = {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}6667encoded = jsonable_encoder(data)68print(encoded) # Already JSON-compatible, returned as-is6970# Complex types that need encoding71complex_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}8081encoded_complex = jsonable_encoder(complex_data)82print(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 encoded90# "set": [1, 2, 3]91# }92```9394### Pydantic Model Encoding9596```python97from fastapi.encoders import jsonable_encoder98from pydantic import BaseModel, Field99from typing import Optional100from datetime import datetime101102class User(BaseModel):103id: int104name: str105email: str106full_name: Optional[str] = Field(None, alias="fullName")107created_at: datetime108is_active: bool = True109110class UserProfile(BaseModel):111user: User112preferences: dict113login_count: int = 0114115# Create model instances116user = User(117id=1,118name="john_doe",119email="john@example.com",120fullName="John Doe",121created_at=datetime.now()122)123124profile = UserProfile(125user=user,126preferences={"theme": "dark", "notifications": True}127)128129# Encode with default settings130encoded = jsonable_encoder(profile)131print(encoded)132133# Encode using aliases134encoded_with_aliases = jsonable_encoder(profile, by_alias=True)135print(encoded_with_aliases["user"]["fullName"]) # Uses alias136137# Exclude certain fields138encoded_minimal = jsonable_encoder(139profile,140exclude={"user": {"created_at"}, "login_count"}141)142143# Include only specific fields144encoded_specific = jsonable_encoder(145profile,146include={"user": {"id", "name"}, "preferences"}147)148149# Exclude unset fields150user_partial = User(id=2, name="jane", email="jane@example.com")151encoded_no_unset = jsonable_encoder(user_partial, exclude_unset=True)152# Won't include created_at if it wasn't explicitly set153154# Exclude None values155user_with_none = User(156id=3,157name="bob",158email="bob@example.com",159full_name=None, # Explicitly set to None160created_at=datetime.now()161)162encoded_no_none = jsonable_encoder(user_with_none, exclude_none=True)163```164165### Database Model Integration166167```python168from fastapi import FastAPI, Depends169from fastapi.encoders import jsonable_encoder170from sqlalchemy.orm import Session171# Assuming SQLAlchemy models172173app = FastAPI()174175@app.get("/users/{user_id}")176def get_user(user_id: int, db: Session = Depends(get_db)):177user = db.query(UserModel).filter(UserModel.id == user_id).first()178179if not user:180raise HTTPException(status_code=404, detail="User not found")181182# Convert SQLAlchemy model to JSON-compatible dict183user_data = jsonable_encoder(user, sqlalchemy_safe=True)184return user_data185186@app.get("/users/{user_id}/profile")187def get_user_profile(user_id: int, db: Session = Depends(get_db)):188user = db.query(UserModel).filter(UserModel.id == user_id).first()189190if not user:191raise HTTPException(status_code=404, detail="User not found")192193# Include related data, exclude sensitive fields194profile_data = jsonable_encoder(195user,196include={197"id", "name", "email", "created_at", "last_login",198"profile": {"bio", "location", "website"},199"posts": {"id", "title", "created_at"}200},201exclude={"password_hash", "email_verified_token"}202)203return profile_data204```205206### Custom Fallback Function207208```python209from fastapi.encoders import jsonable_encoder210import numpy as np211from typing import Any212213# Custom fallback for handling NumPy arrays214def numpy_fallback(obj: Any) -> Any:215if isinstance(obj, np.ndarray):216return obj.tolist()217elif isinstance(obj, np.integer):218return int(obj)219elif isinstance(obj, np.floating):220return float(obj)221else:222# Re-raise the TypeError to use default handling223raise TypeError(f"Object of type {type(obj)} is not JSON serializable")224225# Data with NumPy objects226data_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}232233encoded_numpy = jsonable_encoder(data_with_numpy, fallback=numpy_fallback)234print(encoded_numpy)235# {236# "array": [1, 2, 3, 4],237# "matrix": [[1, 2], [3, 4]],238# "int64": 42,239# "float64": 3.14159240# }241```242243### Response Encoding in Endpoints244245```python246from fastapi import FastAPI, HTTPException247from fastapi.encoders import jsonable_encoder248from fastapi.responses import JSONResponse249250app = FastAPI()251252@app.get("/complex-data")253def get_complex_data():254complex_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": True264}265}266}267268# Encode the complex data structure269encoded_response = jsonable_encoder(complex_response)270return JSONResponse(content=encoded_response)271272@app.post("/process-data")273def process_data(raw_data: dict):274# Process and potentially modify data275processed = {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}284285# Use jsonable_encoder to ensure everything is JSON-compatible286return jsonable_encoder(processed, exclude_none=True)287```288289### Time Delta Formatting Options290291```python292from fastapi.encoders import jsonable_encoder293from datetime import timedelta294295duration_data = {296"short": timedelta(minutes=30),297"medium": timedelta(hours=2, minutes=45),298"long": timedelta(days=5, hours=3, minutes=20)299}300301# ISO 8601 format (default)302iso_encoded = jsonable_encoder(duration_data, timedelta_isoformat="iso8601")303print(iso_encoded)304# {305# "short": "PT30M",306# "medium": "PT2H45M",307# "long": "P5DT3H20M"308# }309310# Float format (total seconds)311float_encoded = jsonable_encoder(duration_data, timedelta_isoformat="float")312print(float_encoded)313# {314# "short": 1800.0,315# "medium": 9900.0,316# "long": 443400.0317# }318```319320## Types321322```python { .api }323from typing import Any, Callable, Dict, List, Optional, Set, Union324325# Include/exclude type for field selection326IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any], None]327328# Fallback function type329FallbackFunc = Callable[[Any], Any]330331# Supported timedelta formats332TimedeltaIsoFormat = Union["iso8601", "float"]333```