Logo

dev-resources.site

for different kinds of informations.

Implement data validation in FastAPI

Published at
10/14/2024
Categories
validation
fastapi
Author
stackpuz
Categories
2 categories in total
validation
open
fastapi
open
Author
8 person written this
stackpuz
open
Implement data validation in FastAPI

Data validation is a crucial aspect of software development, ensuring that input data is accurate and meets the necessary requirements before being processed or stored. This guide will teach you how to use built-in validations in FastAPI with Pydantic models, helping you build secure and reliable applications by leveraging FastAPI's automatic validation features.

Prerequisites

  • Python 3.10

Setup project

pip install fastapi uvicorn email-validator
Enter fullscreen mode Exit fullscreen mode

Project structure

└─ app
   β”œβ”€ __init__.py
   β”œβ”€ main.py
   β”œβ”€ schemas
   β”‚ └─ user.py
   └─ static
      └─ index.html
Enter fullscreen mode Exit fullscreen mode

__init__.py is used to mark the directory as a Python package.

user.py

from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import date

class User(BaseModel):
    id: int
    name: Optional[str] = Field(None, max_length=10)
    email: Optional[EmailStr] = None
    age: Optional[int] = Field(None, ge=1, le=100)
    birthdate: Optional[date] = None
Enter fullscreen mode Exit fullscreen mode

This user.py file defines a User model using Pydantic for validation testing in FastAPI. The model includes the following fields with built-in validation:

  • id: An integer representing the user's ID (required).
  • name: An optional string with a maximum length of 10 characters.
  • email: An optional email field validated using Pydantic's EmailStr type.
  • age: An optional integer that must be between 1 and 100, inclusive.
  • birthdate: An optional date field for the user's birthdate.

main.py

import uvicorn
from fastapi import FastAPI
from fastapi.requests import Request
from fastapi.responses import FileResponse, JSONResponse
from fastapi.exceptions import RequestValidationError
from app.schemas.user import User

app = FastAPI()
@app.get("/")
async def index():
    return FileResponse("app/static/index.html")

@app.post("/submit")
async def submit(user: User):
    return user

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return await get_error(exc)

async def get_error(exc: Exception) -> JSONResponse:
    if isinstance(exc, RequestValidationError):
        errors = {}
        for error in exc.errors():
            field_name = error["loc"][-1]
            errors[field_name] = error["msg"]
        return JSONResponse(errors, 400)
    return exc

if __name__ == " __main__":
    uvicorn.run(app, host="127.0.0.1")
Enter fullscreen mode Exit fullscreen mode

This main.py file sets up a FastAPI application with two main endpoints and custom error handling.

  • The root endpoint (/) serves a static HTML file (index.html) from the app/static directory.
  • The /submit endpoint accepts POST requests with user data validated against the User Pydantic model and returns the submitted user information.
  • A custom exception handler for RequestValidationError is defined, which formats validation errors into a JSON response, mapping field names to their respective error messages.

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="app" class="container">
        <div class="row mt-3">
            <form @submit.prevent="submit()">
                <div class="mb-3 col-12">
                    <label class="form-label" for="id">Id</label>
                    <input id="id" class="form-control form-control-sm" v-model="user.id" />
                    <span v-if="errors.id" class="text-danger">{{ errors.id }}</span>
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="name">Name</label>
                    <input id="name" class="form-control form-control-sm" v-model="user.name" />
                    <span v-if="errors.name" class="text-danger">{{ errors.name }}</span>
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="email">Email</label>
                    <input id="email" class="form-control form-control-sm" v-model="user.email" />
                    <span v-if="errors.email" class="text-danger">{{ errors.email }}</span>
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="age">Age</label>
                    <input id="age" class="form-control form-control-sm" v-model="user.age" />
                    <span v-if="errors.age" class="text-danger">{{ errors.age }}</span>
                </div>
                <div class="mb-3 col-12">
                    <label class="form-label" for="birthdate">Birth Date</label>
                    <input id="birthdate" class="form-control form-control-sm" v-model="user.birthdate" />
                    <span v-if="errors.birthdate" class="text-danger">{{ errors.birthdate }}</span>
                </div>
                <div class="col-12">
                    <input type="button" class="btn btn-sm btn-danger" @click="fill(0)" value="Fill invaid data" />
                    <input type="button" class="btn btn-sm btn-success ms-1" @click="fill(1)" value="Fill vaid data" />
                    <button class="btn btn-sm btn-primary ms-1">Submit</button>
                </div>
                <div v-if="pass" class="alert alert-success mt-3">
                    Validation success!
                </div>
            </form>
        </div>
    </div>
    <script>
        const { createApp } = Vue
        createApp({
            data() {
                return {
                    user: {},
                    errors: {},
                    pass: false
                }
            },
            methods: {
                fill(valid) {
                    this.user.id = (valid ? '1' : undefined)
                    this.user.name = (valid ? 'foo' : 'my name is foo')
                    this.user.email = (valid ? '[email protected]' : 'mail')
                    this.user.age = (valid ? '10' : '101')
                    this.user.birthdate = (valid ? '2000-01-01' : '01012000')
                },
                submit() {
                    fetch('/submit', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify(this.user)
                    }).then(res => {
                        if (res.status == 200) {
                            this.pass = true
                            this.errors = {}
                        }
                        else {
                            res.json().then(err => {
                                this.pass = false
                                this.errors = err
                            })
                        }
                    })
                }
            }
        }).mount('#app')
    </script>
</body>
Enter fullscreen mode Exit fullscreen mode

This index.html file creates a user interface for submitting user data through a form, utilizing Vue.js for interactivity. It features input fields for ID, name, email, age, and birthdate, with immediate feedback for validation errors displayed beneath each field. Users can fill the form with valid or invalid data for testing, and upon submission, a POST request is sent to the /submit endpoint. The interface provides a success message for successful submissions and displays error messages if validation fails. The layout is styled with Bootstrap for a responsive design, enabling easy data input and validation testing with a FastAPI backend.

Run project

uvicorn app.main:app --reload 

Enter fullscreen mode Exit fullscreen mode

Open the web browser and goto http://localhost:8000

You will find this test page.

testing page

Testing

Click "Fill invalid data" and then click "Submit" to see the error messages displayed in the input form.

validation failed

Click "Fill valid data" and then "Submit" again. You should see the validation success message displayed in the input form.

validation success

Conclusion

This article explored implementing basic form validation with FastAPI and Pydantic, enabling you to create reliable and user-friendly applications. By leveraging Pydantic's validation features, you can ensure user input meets specific criteria, such as valid email formats, numerical ranges, and string lengths. These validations catch errors early, providing immediate feedback and improving user experience. Incorporating these techniques will enhance the robustness and usability of your FastAPI application while ensuring data integrity.

Source code: https://github.com/stackpuz/Example-Validation-FastAPI

Create a CRUD Web App in Minutes: https://stackpuz.com

validation Article's
30 articles in total
Favicon
"yup" is the new extra virgin olive oil
Favicon
JavaScript Email Validation Regex: Ensuring Accuracy in User Inputs
Favicon
Simplifying JSON Validation with Ajv (Another JSON Validator)
Favicon
Dynamic string validation using go's text/template package
Favicon
Practical Email Validation Using JavaScript: Techniques for Web Developers
Favicon
Validation in Spring REST Framework (SRF)
Favicon
Terraform Validation Rules: Best Practices & Examples
Favicon
Zod for TypeScript Schema Validation: A Comprehensive Guide
Favicon
AI Image Validation Solutions: A Game-Changer for Quality Control
Favicon
Transform zod error into readable error response
Favicon
β›”Stop Excessive Validation, you are ruining my life hack!
Favicon
zod vs class-validator & class-transformer
Favicon
Animated Login Form with Validation Using HTML, CSS & JavaScript
Favicon
How to work with regular expressions
Favicon
User Form Validation in HTML CSS and JavaScript | JavaScript Form Validation
Favicon
Simplify Form Validation with FormGuardJS: A Lightweight and Flexible Solution
Favicon
moment.js Alternative - Luxon
Favicon
Validating REST requests in a NestJS application and displaying errors in Angular application forms
Favicon
Implement data validation in FastAPI
Favicon
The Definitive Guide to the Constraint Validation API
Favicon
Env-Core: An Easy Way to Validate Environment Variables in Node.js Projects
Favicon
File-Type Validation in Multer is NOT SAFEπŸ™ƒ
Favicon
Guaranteed GxP Compliance: Mastering Validation Testing Strategies
Favicon
Assuring Excellence: The Crucial Benefits of GxP Validation Testing
Favicon
7 Old-School Practices in HTML Should Be Avoided
Favicon
Implement data validation in Spring Boot
Favicon
Implement data validation in Express
Favicon
An easy way to validate DTO's using Symfony attributes
Favicon
Implement data validation in .NET
Favicon
Mastering Data Validation in NestJS: A Complete Guide with Class-Validator and Class-Transformer

Featured ones: