When building an API, validating user input is critical for maintaining data integrity and providing a great user experience. With FastAPI and Pydantic, you can easily validate incoming data and provide clear feedback to users.
In this article, we'll build a simple User Management API with custom validators for:
- Ensuring the
email
field is a valid email. - Checking that
name
contains at least 3 characters. - Verifying that
age
is at least 18 years.
Let's dive in! πββοΈ
π Prerequisites
Before you start, ensure you have the following:
- Python 3.8+
- pip (Python package manager)
Install the required libraries:
pip install fastapi uvicorn pydantic
π The API Features
We'll build an API that:
- Accepts user data: Name, Email, and Age.
-
Validates input data:
- Name must have at least 3 characters.
- Email must be a valid email address.
- Age must be 18 or older.
- Stores users: In-memory for simplicity.
- Provides feedback: Returns clear error messages when validation fails.
π Code Implementation
1οΈβ£ Define the User Model with Validators
Weβll use Pydantic to define the input model and implement custom validation.
from pydantic import BaseModel, EmailStr, validator
class UserCreate(BaseModel):
name: str
email: EmailStr # Automatically validates email format
age: int
# Validator to ensure the name has at least 3 characters
@validator("name")
def name_must_be_valid(cls, value):
if len(value) < 3:
raise ValueError("Name must contain at least 3 characters.")
return value
# Validator to ensure the age is at least 18
@validator("age")
def age_must_be_adult(cls, value):
if value < 18:
raise ValueError("Age must be at least 18 years old.")
return value
2οΈβ£ Initialize the FastAPI App and User Store
We'll create an in-memory list to store users and define the API endpoints.
from fastapi import FastAPI, HTTPException
from typing import List
app = FastAPI()
# In-memory user storage
users = []
@app.post("/users/", response_model=UserCreate)
def create_user(user: UserCreate):
# Check if email is already registered
if any(u['email'] == user.email for u in users):
raise HTTPException(status_code=400, detail="Email already registered")
# Add user to the in-memory database
users.append(user.dict())
return user
@app.get("/users/", response_model=List[UserCreate])
def get_users():
return users
Β 3οΈβ£ Run the Application
Run the app using Uvicorn:
uvicorn main:app --reload
Visit the interactive API documentation at http://127.0.0.1:8000/docs
.
π― Testing the API
Hereβs how you can test the API using cURL
or any HTTP client like Postman or Thunder Client.
β Valid Request
curl -X POST "http://127.0.0.1:8000/users/" \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "john@example.com", "age": 25}'
Response:
{
"name": "John Doe",
"email": "john@example.com",
"age": 25
}
β Invalid Email
curl -X POST "http://127.0.0.1:8000/users/" \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "invalid-email", "age": 25}'
Response:
{
"detail": [
{
"loc": ["body", "email"],
"msg": "value is not a valid email address",
"type": "value_error.email"
}
]
}
β Name Too Short
curl -X POST "http://127.0.0.1:8000/users/" \
-H "Content-Type: application/json" \
-d '{"name": "Jo", "email": "john@example.com", "age": 25}'
Response:
{
"detail": [
{
"loc": ["body", "name"],
"msg": "Name must contain at least 3 characters.",
"type": "value_error"
}
]
}
β Age Below 18
curl -X POST "http://127.0.0.1:8000/users/" \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "john@example.com", "age": 15}'
Response:
{
"detail": [
{
"loc": ["body", "age"],
"msg": "Age must be at least 18 years old.",
"type": "value_error"
}
]
}
Β β Email Already Registered
First, create a user with the following request:
curl -X POST "http://127.0.0.1:8000/users/" \
-H "Content-Type: application/json" \
-d '{"name": "John Doe", "email": "john@example.com", "age": 25}'
Then, try creating another user with the same email:
curl -X POST "http://127.0.0.1:8000/users/" \
-H "Content-Type: application/json" \
-d '{"name": "Jane Doe", "email": "john@example.com", "age": 30}'
Β Response:
{
"detail": "Email already registered"
}
π Key Features of This Example
-
Validation with Pydantic:
- Automatic validation for email format.
- Custom validators for name and age.
-
Clear Error Messages:
- Each validation error is returned with a specific message, making it easier to debug and fix input issues.
-
Scalable Design:
- The approach can be extended to include more fields, validations, or even integrate a database.
π Wrapping Up
Using FastAPI and Pydantic, you can implement powerful validation logic with minimal effort. This approach not only ensures data integrity but also improves the developer and user experience with clear and actionable error messages.
What custom validators would you add to this API? Share your thoughts in the comments! π
Happy coding! π¨βπ»π©βπ»
Top comments (1)
Thanks for sharing article.