Lesson 8 of 45 ยท FastAPI Basics
Body - Fields
Learn to add validation and metadata to Pydantic model fields using Field(). Master field-level constraints, descriptions, and advanced validation.
Open this lesson in the editor โWhat you'll learn
- Import and use Field from pydantic for model attributes
- Add validation constraints to model fields (gt, max_length, etc.)
- Include metadata like titles and descriptions for better documentation
- Understand the relationship between Field, Query, Path, and Body
Body - Fields
๐ฏ What You'll Learn
This lesson follows the official FastAPI "Body - Fields" tutorial exactly. You'll learn how to use Pydantic's Field() function to add validation and metadata to model attributes, making your APIs more robust and well-documented.
By the end of this lesson, you'll understand how to:
- Import and use
Fieldfrom pydantic for model attributes - Add validation constraints to model fields (gt, max_length, etc.)
- Include metadata like titles and descriptions for better documentation
- Understand the relationship between Field, Query, Path, and Body
๐ Import Field
First, you need to import Field from pydantic:
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
โ ๏ธ Important: Notice that Field is imported directly from pydantic, not from fastapi like Query, Path, and Body.
๐ง Declare Model Attributes with Field
You can use Field with model attributes to add validation and metadata:
class Item(BaseModel):
name: str
description: Union[str, None] = Field(
default=None, title="The description of the item", max_length=300
)
price: float = Field(gt=0, description="The price must be greater than zero")
tax: Union[float, None] = None
Field Parameters
Field works the same way as Query, Path, and Body - it accepts the same validation parameters:
- Validation constraints:
gt,ge,lt,le,min_length,max_length, etc. - Metadata:
title,description,example, etc. - Default values:
default,default_factory
๐ฏ Complete Example
Following the official FastAPI tutorial:
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = Field(
default=None, title="The description of the item", max_length=300
)
price: float = Field(gt=0, description="The price must be greater than zero")
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(embed=True)):
results = {"item_id": item_id, "item": item}
return results
Request Body Structure
With Body(embed=True), the request expects:
{
"item": {
"name": "Laptop",
"description": "High-performance gaming laptop",
"price": 999.99,
"tax": 99.99
}
}
๐ Key Concepts
Field vs Function Parameters
Notice the similarity between model attributes with Field and function parameters:
Model attribute with Field:
price: float = Field(gt=0, description="The price must be greater than zero")
Function parameter with Path:
item_id: int = Path(gt=0, description="The ID of the item")
Both follow the same pattern: parameter: type = ValidationFunction(constraints)
Validation Benefits
Field validation provides:
- Automatic validation: Invalid data returns HTTP 422 with detailed error messages
- Type conversion: Automatic conversion between compatible types
- Documentation: Metadata appears in OpenAPI schema and interactive docs
- IDE support: Better autocomplete and type checking
Technical Details
Query,Path,Bodycreate objects of subclasses ofParamclassParamis a subclass of Pydantic'sFieldInfoclassFieldreturns an instance ofFieldInfodirectly- All use the same underlying validation system
๐ก Best Practices
Validation Constraints
class Item(BaseModel):
name: str = Field(min_length=1, max_length=100)
price: float = Field(gt=0, le=1000000) # Positive, reasonable max
quantity: int = Field(ge=1, le=1000) # At least 1, reasonable max
email: str = Field(regex=r'^[\w\.-]+@[\w\.-]+\.\w+$')
Descriptive Metadata
class User(BaseModel):
username: str = Field(
title="Username",
description="Unique identifier for the user",
min_length=3,
max_length=50,
example="johndoe"
)
age: int = Field(
title="Age",
description="Age in years",
ge=0,
le=150,
example=25
)
Optional Fields with Defaults
class Item(BaseModel):
name: str
description: Union[str, None] = Field(
default=None,
title="Item Description",
max_length=500
)
is_active: bool = Field(default=True, description="Whether item is active")
๐ Add Extra Information
You can include additional metadata in Field that will appear in the generated JSON Schema:
class Item(BaseModel):
name: str = Field(
title="Item Name",
description="The name of the item",
example="Laptop"
)
price: float = Field(
gt=0,
description="Price in USD",
example=999.99
)
โ ๏ธ Warning: Extra keys passed to Field will be present in the OpenAPI schema. Some OpenAPI tools may not work with non-standard keys.
๐ฏ Validation Examples
Valid Request
{
"item": {
"name": "Gaming Laptop",
"description": "High-performance laptop for gaming",
"price": 1299.99
}
}
โ Result: Success - all validations pass
Invalid Requests
Negative price:
{
"item": {
"name": "Laptop",
"price": -100
}
}
โ Result: HTTP 422 - "ensure this value is greater than 0"
Description too long:
{
"item": {
"name": "Laptop",
"description": "x".repeat(400), // Over 300 characters
"price": 999.99
}
}
โ Result: HTTP 422 - "ensure this value has at most 300 characters"
๐ What's Next?
In the next lesson, you'll learn about Body - Nested Models, where you'll discover how to create complex nested Pydantic models with lists, sets, and deeply nested structures.
๐ Additional Resources
Hint
Import Field from pydantic (not fastapi). Use Field() to add validation like gt=0 for positive numbers and max_length for strings.
Now write it
The editor runs a real FastAPI server and grades your code against this lesson's own endpoints.
Start Body - Fields