DEV Community

Cover image for Day 3: Request Body & Pydantic Explained with Real-World Context
Utkarsh Rastogi
Utkarsh Rastogi

Posted on • Edited on

1 1

Day 3: Request Body & Pydantic Explained with Real-World Context

Welcome to Day 3 of our FastAPI journey! Yesterday, we explored how to use path parameters to handle dynamic URLs.

Today, we’re entering the world of Request Bodies and Pydantic — the backbone of data validation in FastAPI.


🧠 Why Do We Need Request Bodies?

Let’s imagine you're building an online registration form for a new user. You need details like name, email, and age. These details are not passed in the URL but rather sent in the body of a POST request.

This is where request bodies and Pydantic models come into play in FastAPI.


🧩 Real-World Analogy: Pydantic is the Bouncer at a Club

Think of your API like a nightclub. You can’t just let anyone in. The bouncer at the door checks if you're:

  • Old enough (age)
  • On the list (valid email)
  • Actually a real person (non-empty name)

Just like that, Pydantic is your API’s gatekeeper — it checks if the incoming request body has the correct structure and data types.


🔧 Step-by-Step: Create a /user POST Endpoint

We'll create a FastAPI app that accepts a JSON body with user details.

📁 Create a file called user.py:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 🎯 Step 1: Define your request body schema using Pydantic
class User(BaseModel):
    name: str
    email: str
    age: int

# 🎯 Step 2: Create a POST endpoint to accept the request body
@app.post("/user")
def create_user(user: User):
    return {
        "message": f"Welcome, {user.name}!",
        "email": user.email,
        "age": user.age
    }
Enter fullscreen mode Exit fullscreen mode

🚀 Test Your Endpoint

🖥️ Start the FastAPI server:

uvicorn user:app --host 0.0.0.0 --port 9002 --reload
Enter fullscreen mode Exit fullscreen mode

🌐 Open your browser and visit the interactive docs:

http://localhost:9002/docs

📤 Try sending this sample JSON:

{
  "name": "Utkarsh",
  "email": "utkarsh@example.com",
  "age": 28
}
Enter fullscreen mode Exit fullscreen mode

Input

Output:

Output

FastAPI will automatically validate the request and return a structured response or helpful error messages.


🧪 Add Validation with Pydantic

Let’s enhance the model with proper validation using EmailStr, default values, and field constraints.

🔧 Prerequisite: Install email-validator

To use EmailStr for validating emails, you must install the email-validator package.

Run this command in your terminal:

pip install pydantic[email]
Enter fullscreen mode Exit fullscreen mode

🔧 Step-by-Step: Create a /user POST Endpoint

We'll create a FastAPI app that accepts a JSON body with user details.

📁 Create a file called user.py:

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, Field
from typing import Optional

app = FastAPI()

class User(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    email: EmailStr
    age: Optional[int] = Field(None, ge=18, le=100)


@app.post("/user")
def create_user(user: User):
    return {
        "message": f"Welcome, {user.name}!",
        "email": user.email,
        "age": user.age
    }
Enter fullscreen mode Exit fullscreen mode

🔍 Explanation:

  • name: Required string with a minimum length of 2 and a maximum of 50.
  • email: Must be a valid email address (EmailStr from Pydantic).
  • age: Optional integer; if provided, it must be between 18 and 100.

🚀 Test Your Endpoint

🖥️ Start the FastAPI server:

uvicorn user:app --host 0.0.0.0 --port 9004 --reload
Enter fullscreen mode Exit fullscreen mode

🌐 Open your browser and visit the interactive docs:

http://localhost:9004/docs

📤 Try sending this sample JSON:

{
  "name": "Utkarsh",
  "email": "utkarsh@example.com",
  "age": 16
}
Enter fullscreen mode Exit fullscreen mode

Input Age

Output:

Output Error


🌍 Real-World Example – Feedback API

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, Field

app = FastAPI()

class Feedback(BaseModel):
    name: str
    email: EmailStr
    message: str = Field(..., min_length=10)

@app.post("/feedback")
def submit_feedback(feedback: Feedback):
    return {
        "status": "received",
        "from": feedback.name,
        "email": feedback.email
    }
Enter fullscreen mode Exit fullscreen mode

Input:

{
  "name": "Utkarsh",
  "email": "Utkarsh@email.com",
  "message": "Great job with the FastAPI series!"
}

Enter fullscreen mode Exit fullscreen mode

Output:

Job


📦 Nested Models Example – Customer with Address

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Address(BaseModel):
    city: str
    pincode: int

class Customer(BaseModel):
    name: str
    address: Address

@app.post("/customer")
def create_customer(customer: Customer):
    return {"msg": f"{customer.name} from {customer.address.city} added."}

Enter fullscreen mode Exit fullscreen mode

Input:

{
  "name": "Utkarsh",
  "address": {
    "city": "Mumbai",
    "pincode": 110
  }
}

Enter fullscreen mode Exit fullscreen mode

Output:

Feefdback


🧠 Recap

Concept Purpose
BaseModel Define and validate data models
EmailStr Validate email format
Optional Make fields optional
Field() Add constraints like min, max, default
Nested Models Model complex JSON structures

🙏 Credits

Huge thanks to the FastAPI Official Documentation by Sebastián Ramírez (@tiangolo) — the best place to learn and explore everything about FastAPI.


👨‍💻 About Me

Hey there! I’m Utkarsh Rastogi, an AWS Community Builder and passionate cloud-native enthusiast who loves building scalable backend systems and sharing knowledge with the community.

🔗 Connect with me: Utkarsh Rastogi


💬 Share Your Thoughts – I'd Love Your Feedback!

If you enjoyed today's post or learned something new, I'd truly appreciate it if you leave a comment or share your thoughts 👇

Your feedback, questions, or even a quick “🔥 Loved this!” keeps me motivated to continue this journey and share more in the upcoming #FastAPIDaily posts.

What did you find most helpful?

Anything you'd like explained in the next part?

Suggestions for improvement? I’m all ears! 🙌

Let’s grow and learn together — one FastAPI day at a time 🚀


Warp.dev image

Warp is the highest-rated coding agent—proven by benchmarks.

Warp outperforms every other coding agent on the market, and gives you full control over which model you use. Get started now for free, or upgrade and unlock 2.5x AI credits on Warp's paid plans.

Download Warp

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

Gen AI apps are built with MongoDB Atlas

Gen AI apps are built with MongoDB Atlas

MongoDB Atlas is the developer-friendly database for building, scaling, and running gen AI & LLM apps—no separate vector DB needed. Enjoy native vector search, 115+ regions, and flexible document modeling. Build AI faster, all in one place.

Start Free

👋 Kindness is contagious

Explore this insightful write-up, celebrated by our thriving DEV Community. Developers everywhere are invited to contribute and elevate our shared expertise.

A simple "thank you" can brighten someone’s day—leave your appreciation in the comments!

On DEV, knowledge-sharing fuels our progress and strengthens our community ties. Found this useful? A quick thank you to the author makes all the difference.

Okay