Post Request with Pydantic usage (input validator)

Post Request by using Pydantic

Pydantic

  • Python library that is used for data modeling, data parsing and has efficient error handling.
  • Pydantics is commonly used as a resource for data validation and how to handle data coming to our FastAPI application.

Pydantic implementation mechanism

  • Create a different request model for data validation
  • Field data validation on each variable/element
  • BaseModel is the Pydantics BaseModel class which will provide facility to validate data.
  • Field is the keyword to do it. As it will help to provide constraints for data validation.
  • sample
class BookRequest(BaseModel):
    id: int = Field(gt=0)
    title: str = Field(min_length=3)
    author: str = Field(min_length=1)
    description: str = Field(min_length=1, max_length=100)
    rating: int = Field(gt=0, lt=5)

Book Request and Book Conversion

  • We will convert the Pydantic Request into a Book
  • Example for post request method
@app.post("/create_book")
async def create_book(book_request: BookRequest):
    new_book = BOOK(**book_request.dict())
    BOOKS.append(new_book)

Note: ** will pass key value pair from BookRequest into Book constructor.

Post Request without validation: 

No input validation code and result:
It will allow to insert any kind of data which we don't want so we need to validate input data before inserting it to our data store.

from fastapi import FastAPI, Body
from books3 import Book

app = FastAPI()

BOOKS = [
    Book(id=1, title="DSA with Java", author="Puneet Kumar Singh",
description="A comprehensive guide to Data Structures and Algorithms using Java.",
rating=5),
    Book(id=2, title="Python Programming", author="Puneet Kumar Singh",
description="An introduction to Python programming for beginners.", rating=4),
    Book(id=3, title="Machine Learning Basics", author="Puneet Kumar Singh",
description="Understanding the fundamentals of Machine Learning.", rating=4),
    Book(id=4, title="Web Development with FastAPI", author="Ramesh Jha",
description="Building web applications using FastAPI.", rating=3),
    Book(id=5, title="Data Science with Python", author="Kalidas",
description="A guide to Data Science using Python.", rating=2),
    Book(id=6, title="Advanced Java Programming", author="Kalpana Gupta",
description="Deep dive into advanced concepts of Java programming.", rating=1)
]

@app.get("/books/") # static path to get all books
async def read_all_books():
    """
    This function returns the list of all books.
    """
    return BOOKS

@app.post("/create_book")
async def create_book(book_request=Body()):
    BOOKS.append(book_request)



Code after input validation through Pydantic:

Validation code:
# using pydantic to validate input data at the time of post request
from pydantic import BaseModel, Field

class BookRequest(BaseModel):
    id: int = Field(gt=0)
    title: str = Field(min_length=3)
    author: str = Field(min_length=1)
    description: str = Field(min_length=1, max_length=100)
    rating: int = Field(gt=0,lt=5)

main.py
from fastapi import FastAPI, Body
from books3 import Book
from datavalidatorhelper import BookRequest

app = FastAPI()

BOOKS = [
    Book(id=1, title="DSA with Java", author="Puneet Kumar Singh",
description="A comprehensive guide to Data Structures and Algorithms using Java.",
rating=5),
    Book(id=2, title="Python Programming", author="Puneet Kumar Singh",
description="An introduction to Python programming for beginners.", rating=4),
    Book(id=3, title="Machine Learning Basics", author="Puneet Kumar Singh",
description="Understanding the fundamentals of Machine Learning.", rating=4),
    Book(id=4, title="Web Development with FastAPI", author="Ramesh Jha",
description="Building web applications using FastAPI.", rating=3),
    Book(id=5, title="Data Science with Python", author="Kalidas",
description="A guide to Data Science using Python.", rating=2),
    Book(id=6, title="Advanced Java Programming", author="Kalpana Gupta",
description="Deep dive into advanced concepts of Java programming.", rating=1)
]

@app.get("/books/") # static path to get all books
async def read_all_books():
    """
    This function returns the list of all books.
    """
    return BOOKS

""" post request without any input validation
@app.post("/create_book")
async def create_book(book_request=Body()):
    BOOKS.append(book_request)
"""

#post request with input validator
@app.post("/creat_book")
async def create_book(book_request: BookRequest):
    new_book = Book(**book_request.model_dump())
# new_book = Book(**book_request.dict()) -> if you are using pydantic version
1 else the model_dump() for pydentic version 2.
    BOOKS.append(book_request)


Evidence of validation:

Correct input entry:

If need to have extra validation for id column where it must be greater than the last entry.
from fastapi import FastAPI, Body
from books3 import Book
from datavalidatorhelper import BookRequest

app = FastAPI()

BOOKS = [
    Book(id=1, title="DSA with Java", author="Puneet Kumar Singh",
description="A comprehensive guide to Data Structures and Algorithms using Java.",
rating=5),
    Book(id=2, title="Python Programming", author="Puneet Kumar Singh",
description="An introduction to Python programming for beginners.", rating=4),
    Book(id=3, title="Machine Learning Basics", author="Puneet Kumar Singh",
description="Understanding the fundamentals of Machine Learning.", rating=4),
    Book(id=4, title="Web Development with FastAPI", author="Ramesh Jha",
description="Building web applications using FastAPI.", rating=3),
    Book(id=5, title="Data Science with Python", author="Kalidas",
description="A guide to Data Science using Python.", rating=2),
    Book(id=6, title="Advanced Java Programming", author="Kalpana Gupta",
description="Deep dive into advanced concepts of Java programming.", rating=1)
]

@app.get("/books/") # static path to get all books
async def read_all_books():
    """
    This function returns the list of all books.
    """
    return BOOKS

""" post request without any input validation
@app.post("/create_book")
async def create_book(book_request=Body()):
    BOOKS.append(book_request)
"""

#post request with input validator
@app.post("/creat_book")
async def create_book(book_request: BookRequest):
    new_book = Book(**book_request.model_dump())
# new_book = Book(**book_request.dict()) ->
if you are using pydantic version 1 else the model_dump() for pydentic version 2.
    # BOOKS.append(new_book) -> it will store the valid input dump but you can have
duplicate ids.
    BOOKS.append(find_book_id(new_book)) # It will add latest id sequence number
to id automatically and will overwrite the provided input so you
don't need to bother about the id value sequence.

def find_book_id(book: Book):
    if len(BOOKS) > 0:
        book.id = BOOKS[-1].id + 1
    else:
        book.id = 1
    return book

Smart code of line:
def find_book_id(book: Book):
    book.id=1 if len(BOOKS) == 0 else BOOKS[-1].id + 1
    return book



Code to make id as optional:
id: optional[int] = None

Exact code:
# using pydantic to validate input data at the time of post request
from pydantic import BaseModel, Field
from typing import Optional

class BookRequest(BaseModel):
    id: Optional[int] = None
    title: str = Field(min_length=3)
    author: str = Field(min_length=1)
    description: str = Field(min_length=1, max_length=100)
    rating: int = Field(gt=0,lt=6)

Result:



Swagger Pydantic Configuration

  • We can config what we need to see in schema
  • We can even modify example value to help us to understand the use of column in swagger by using Pydantic.
  • If we provide description to Field keyword then we can see the changes in schema.
  • If we define model_config json object then we can modify the example value information.

Code:

# using pydantic to validate input data at the time of post request
from pydantic import BaseModel, Field
from typing import Optional

class BookRequest(BaseModel):
    id: Optional[int] = Field(description="Id is optional so you can skip it",
default=None)
    title: str = Field(min_length=3)
    author: str = Field(min_length=1)
    description: str = Field(min_length=1, max_length=100)
    rating: int = Field(gt=0,lt=6)

    model_config = {
        "json_schema_extra":{
            "example":{
                "title": "Enter the book name with minimum 3 characters.",
                "author": "Provide author name please. With minimum 1 character.",
                "description": "book description please. Characters
range is from 1 to 100.",
                "rating": "Please provide rating in between 1 to 5"
            }
        }
    }

Result:





Comments

Popular posts from this blog

CRUD Assignment

Path Parameter Data Validation | Query Parameter Data Validation