Stop duplicating your Pydantic schemas. Map FastAPI request parameters into a single DTO.
Project description
🎩 FastAPI Magic DTO
Stop duplicating your Pydantic schemas. Keep your Application layer pure.
fastapi-magic-dto is a lightweight utility that allows you to map FastAPI request parameters (Path, Query, Header, Cookie, and Body) directly into a single, clean DTO (Data Transfer Object) without polluting your business logic with HTTP-specific dependencies.
🤬 The Problem
When building layered architectures (Clean Architecture, CQRS, Hexagonal), your Application layer (Interactors/Use Cases) should know nothing about HTTP.
Normally, to extract data from multiple HTTP locations (like a User ID from the URL Path, and the User Name from the JSON Body), FastAPI forces you to either:
- Write two separate schemas (one for FastAPI, one for the Application layer) and map them manually.
- Pollute your Application DTO with
fastapi.Pathandfastapi.Query.
❌ Bad (Leaking HTTP into Domain)
from fastapi import Path, Body
from pydantic import BaseModel
class UpdateUserDTO(BaseModel):
user_id: int = Path(...) # 🔴 Domain now depends on FastAPI!
name: str = Body(...)
✨ The Solution
fastapi-magic-dto allows you to write a pure Pydantic DTO (or standard Dataclass), and use an elegant type hint at the Router level to tell FastAPI exactly where to find the data.
✅ Good (Pure Domain + MagicDTO)
from pydantic import BaseModel
from fastapi_magic_dto import MagicDTO, P
# 1. Pure Application DTO. Zero HTTP logic.
class UpdateUserDTO(BaseModel):
user_id: int
name: str
# 2. FastAPI Router mapping HTTP to the DTO
@app.put("/users/{user_id}")
async def update_user(
data: MagicDTO[UpdateUserDTO, P.user_id]
):
# `user_id` is extracted from the URL Path.
# `name` is automatically extracted from the JSON Body.
return data
📦 Installation
pip install fastapi-magic-dto
🚀 Features
- Zero Duplication: Write one DTO for both validation and business logic.
- Perfect OpenAPI (Swagger): Fully compatible with FastAPI's automatic schema generation.
Path,Query, andBodyparameters appear exactly where they should. - Type Checker Friendly: Mypy, Pylance, and Pyright will see the correct types. Autocomplete works perfectly.
- Dataclass Support: Works natively with standard Python
@dataclass—no Pydantic required! - Everything Supported: Extract data from
Path(P),Query(Q),Header(H),Cookie(C), and JSONBody.
🛠 Usage & Markers
The library provides 4 intuitive markers to define the origin of your fields:
| Marker | HTTP Location | Example |
|---|---|---|
P |
Path | P.item_id maps to /items/{item_id} |
Q |
Query | Q.limit maps to ?limit=10 |
H |
Header | H.user_agent maps to User-Agent: ... |
C |
Cookie | C.session maps to Cookie: session=... |
Note: Any field in your DTO that is not explicitly marked will automatically be extracted from the JSON Request Body.
📖 Complete Example (The Frankenstein)
You can extract data from everywhere simultaneously into a single DTO.
class CreateItemDTO(BaseModel):
category_id: int
name: str = Field(..., min_length=2, max_length=100)
price: float = Field(...)
class CreateItemInteractor:
async def __call__(self, data: CreateItemDTO) -> dict:
# Business logic goes here (e.g., saving to the database)
return {
"status": "success",
"message": f"Item '{data.name}' created in category {data.category_id}.",
"item_data": data.model_dump(),
}
create_item_interactor = CreateItemInteractor()
app = FastAPI()
@app.post("/items/{category_id}", tags=["Items"])
async def create_item(
# MagicDTO extracts `category_id` from Path, and `name`/`price` from Body
data: MagicDTO[CreateItemDTO, P.category_id],
) -> dict:
return await create_item_interactor(data)
🐍 Using Standard Dataclasses
Don't want to use Pydantic? No problem. MagicDTO fully supports standard Python dataclasses.
from dataclasses import dataclass
from fastapi_magic_dto import MagicDTO, P, Q
@dataclass
class SearchDTO:
category_id: int
limit: int = 10
search_term: str = ""
@app.get("/search/{category_id}")
async def search_items(
data: MagicDTO[SearchDTO, P.category_id, Q.limit, Q.search_term]
):
return data
📝 License
MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_magic_dto-0.1.0.tar.gz.
File metadata
- Download URL: fastapi_magic_dto-0.1.0.tar.gz
- Upload date:
- Size: 16.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.10 {"installer":{"name":"uv","version":"0.9.10"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a152e2fee005a7289735284be2bac97a99161781094ccd6a977184dc1d869f87
|
|
| MD5 |
e6aa63abdbae48563fd966cfec51a9df
|
|
| BLAKE2b-256 |
af61cdfaf138dd167dd5a445904bd6e58bcaff51c53caab0cfd75d1ac7358396
|
File details
Details for the file fastapi_magic_dto-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_magic_dto-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.10 {"installer":{"name":"uv","version":"0.9.10"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1feae9f2e4374b5d3c3acc1e220d3b127e61499df9ca96a290ccc9570449faa2
|
|
| MD5 |
ce8155d91671296a177b8f29451c7ea9
|
|
| BLAKE2b-256 |
70bd56f4c03a73bf2cd95fcde845fe1598fcdd7839dff0b9ac1cba78e50c5688
|