Last modified: Dec 01, 2025 By Alexander Williams

FastAPI Validation with Pydantic Models

Data validation is critical for web APIs. It ensures your application receives clean and correct data. FastAPI leverages Pydantic for this task.

Pydantic is a Python library for data parsing and validation. It uses Python type hints. This makes your code robust and self-documenting.

This guide teaches you to use Pydantic models effectively. You will build secure and reliable APIs. Let's start with the basics.

Why Validation Matters in FastAPI

APIs interact with clients and other services. They send and receive data. Invalid data can cause crashes or security issues.

Validation checks incoming data against rules. It ensures data types, formats, and ranges are correct. This protects your application logic.

FastAPI automatically validates request data. It uses the Pydantic models you define. Invalid requests get detailed error messages.

This improves developer experience and API security. It is a core feature of FastAPI's design.

Setting Up Your FastAPI Project

First, ensure FastAPI and Pydantic are installed. If not, see our guide on How to Install FastAPI in Python.

Create a new Python file. Import the necessary modules. We'll build a simple user registration API.


# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr, Field
from typing import Optional

# Initialize the FastAPI app
app = FastAPI()

Defining Your First Pydantic Model

A Pydantic model is a class inheriting from BaseModel. Define attributes with type hints. Add validation constraints.

Let's create a UserCreate model. It will validate data for creating a new user.


class UserCreate(BaseModel):
    # Basic field with type hint
    username: str
    # Email validation using EmailStr
    email: EmailStr
    # Field with constraints: minimum length
    password: str = Field(..., min_length=8)
    # Optional field with a default value
    age: Optional[int] = Field(None, ge=13, le=120)

The Field function adds extra validation. min_length=8 ensures the password is strong. ge and le set numeric ranges.

EmailStr validates email format automatically. This is a powerful Pydantic feature.

Using the Model in a Path Operation

Now, use the model in a POST endpoint. FastAPI will automatically validate the request body.


@app.post("/users/")
async def create_user(user: UserCreate):
    """
    Create a new user.
    The 'user' parameter is automatically validated.
    """
    # If validation passes, we receive a valid 'user' object
    # Simulate saving to a database
    user_data = user.dict()
    # In a real app, you would hash the password here.
    return {"message": "User created successfully", "user_data": user_data}

Declare the user parameter with the UserCreate type. FastAPI handles the rest. It reads the JSON body.

It validates it against the model. If valid, the function runs. If invalid, FastAPI returns a 422 error with details.

Testing Validation with Invalid Data

Let's test the endpoint with bad data. We'll use a short password and an invalid email.

Send a POST request to /users/ with this JSON body.


{
  "username": "john_doe",
  "email": "not-an-email",
  "password": "123",
  "age": 10
}

FastAPI will reject this request. It returns a structured error response.


{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "value is not a valid email address",
      "type": "value_error.email"
    },
    {
      "loc": ["body", "password"],
      "msg": "ensure this value has at least 8 characters",
      "type": "value_error.any_str.min_length",
      "ctx": {"limit_value": 8}
    },
    {
      "loc": ["body", "age"],
      "msg": "ensure this value is greater than or equal to 13",
      "type": "value_error.number.not_ge",
      "ctx": {"limit_value": 13}
    }
  ]
}

The errors are clear and actionable. Each invalid field gets a specific message. This helps frontend developers debug.

Advanced Validation Techniques

Pydantic offers many validators. Use custom validators for complex logic.

Define a method with the @validator decorator. It can check relationships between fields.


from pydantic import validator

class Product(BaseModel):
    name: str
    price: float
    discount_price: Optional[float] = None

    @validator('discount_price')
    def validate_discount(cls, v, values):
        # 'v' is the value of discount_price
        # 'values' contains already-validated fields
        if v is not None:
            if 'price' in values and v >= values['price']:
                raise ValueError('Discount price must be less than original price')
        return v

This validator ensures the discount is lower than the original price. It showcases cross-field validation.

You can also use regular expressions. Use the constr type with a regex pattern.

Integrating with Databases and Other Operations

Pydantic models are not just for input. Use them for output responses too. This ensures consistent data shapes.

You might have a UserInDB model for database records. It can exclude the password field for safety.

For database operations, combine Pydantic with SQLAlchemy. See our FastAPI SQLAlchemy CRUD Guide for details.

Similarly, for handling file data, validation is key. Our FastAPI File Upload Download Tutorial covers this.

Best Practices for Effective Validation

Keep your models focused. Create separate models for creation, update, and response. This is the API equivalent of separation of concerns.

Use inheritance to avoid duplication. A base UserBase model can hold common fields.

Always sanitize and hash sensitive data like passwords. Validation is not a substitute for security.

For complex applications, consider using Pydantic's Settings management. It validates configuration data.

Remember, validation is the first line of defense. Pair it with authentication. Learn more in our FastAPI JWT Authentication Python Tutorial.

Conclusion

Pydantic models are a cornerstone of FastAPI development. They provide automatic, robust data validation.

You learned to define models with type hints and constraints. You saw how to use them in path operations.

We explored custom validators and error handling. This ensures your API is reliable and developer-friendly.

Start by defining clear models for your data. Use validation to build trust in your API endpoints. Your applications will be more secure and maintainable.

Combine this with other FastAPI features for powerful backends. Happy coding!