Back to Blog
Lesson 43 of the Python: Programming from Zero with Python course
PythonAugust 31, 20264 min read

Handling API Payloads: Pydantic Validation for FastAPI

Learn how to use Pydantic for data validation in your FastAPI projects. Turn raw JSON into reliable Python objects and handle malformed requests with ease.

PythonFastAPIPydanticAPIBackendData Validation
Close-up of software development tools displaying code and version control systems on a computer monitor.

Previously in this course, we learned about defining API endpoints and setting up FastAPI. Today, we’re moving from simply receiving data to trusting it.

When you build a backend, your API is the front door to your application. If you let anyone walk in with whatever data they want, your database will quickly turn into a chaotic mess. Data validation is the process of ensuring that incoming requests match the structure and types your application expects.

Why Use Pydantic?

In Python, we often use dictionaries to store data. However, dictionaries are "loose"—they don't care if a field is missing or if an integer suddenly becomes a string. Pydantic is a library that allows us to define "models" (schemas) that act as a contract for our data.

When you pass a Pydantic model to a FastAPI route, the framework automatically validates the incoming request body against that model. If the data is invalid, FastAPI returns a helpful, automatic 422 Unprocessable Entity error to the client. This is the industry standard for input validation and schema enforcement, ensuring that your core logic only ever sees clean, typed data.

Defining Your First Pydantic Model

To use Pydantic, ensure you have it installed (pip install pydantic). We define a model by inheriting from BaseModel.

PYTHON
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float
    is_available: bool = True  # Default value

In this example, name must be a string, price a float, and is_available a boolean. If a user sends a string where a float is expected, Pydantic will attempt to coerce it (e.g., "19.99" becomes 19.99). If it can't, it raises a validation error.

Integrating Pydantic with FastAPI

Let's update our project to accept a POST request for a new data entry. We’ll integrate this into our running data-processing tool to ensure we are adding valid items to our dataset.

PYTHON
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Entry(BaseModel):
    id: int
    title: str
    score: float

@app.post("/entries/")
async def create_entry(entry: Entry):
    # Because of the type hint, CE9178">'entry' is already an instance of the Entry class
    return {"message": "Entry created successfully", "data": entry}

When a user sends a JSON object like {"id": 1, "title": "Test", "score": 9.5}, FastAPI parses it, validates it against the Entry model, and passes it to your function as an object. You can access data using dot notation (e.g., entry.title) rather than dictionary keys.

Handling Malformed JSON

What happens when a client sends garbage? Suppose a user sends {"id": "not-an-int", "title": "Bad Data"}.

  1. Automatic Error Responses: FastAPI sees that the id is not an integer and returns a 422 error automatically.
  2. Detailed Feedback: The response body will contain a JSON object explaining exactly which field failed and why (e.g., "value is not a valid integer").

This removes the need for you to write repetitive if statements to check for the existence or type of every single field. It's similar to how we manage LLM guardrails by enforcing structured data output before it hits the rest of our system.

Hands-on Exercise

  1. Create a new file models.py and define an Item model with fields name (str), quantity (int), and price (float).
  2. In your main FastAPI file, import this model.
  3. Create a POST endpoint /items/ that accepts this model.
  4. Try sending a request via Postman or curl with a missing field, or an incorrect type, and observe the 422 error response.

Common Pitfalls

  • Ignoring Defaults: If you don't provide a default value (like is_available: bool = True), the field is required. Clients must provide it.
  • Over-Trusting Input: Pydantic validates structure, not business logic. If you need price to be greater than zero, you should use Pydantic's @field_validator to enforce that constraint.
  • Mismatched Types: Don't confuse Python's built-in typing module with Pydantic; always use the BaseModel for request/response payloads.

FAQ

Q: Can I use Pydantic models for responses, too? A: Yes! If you use the model as a return type annotation, FastAPI will automatically filter your data to ensure only the fields defined in the model are sent to the client.

Q: What if I want an optional field? A: Use typing.Optional (or | None in Python 3.10+). Example: description: str | None = None.

Recap

We've moved from untrusted, manual dictionary parsing to robust, automated schema validation. By using Pydantic, we ensure our API is self-documenting and resilient against malformed data. Your backend is now much safer and significantly easier to maintain.

Up next: We'll learn how to refine our API access by using Query Parameters and Path Variables to filter and target specific data subsets.

Similar Posts