FastAPIInteractiveAll tracks

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 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

๐Ÿ“š 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, Body create objects of subclasses of Param class
  • Param is a subclass of Pydantic's FieldInfo class
  • Field returns an instance of FieldInfo directly
  • 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