# Flask-Pydantic For Data Validation

Hello Folks,

This is My First Blog on Hash node. Hope you will enjoy the read.

## Introduction Of Flask-Pydantic Extension

Before knowing about Flask-Pydantic Extension, I want you all to know about what is pydantic? pydantic package is used for data validation using Python type hints and Flask-Pydantic is Flask Extension for integration of the awesome pydantic package with Flask.

Suppose you are building blog API with Flask then there is a feature where the user can create a post and when the user is sending the data to the server then there is a particular format in which we want the user to send the data, for example, we want the user to send the title of the blog in string format and what if the user is sending the title of type integer this may cause the error, so we want to tell the user to send the data in a particular format and some times we don't want the user to send only few information and miss the other important information when user wants to create a post then our API has some required parameters which need to be passed by the user such as title, subtitle and content and we want the user to send all the data and missing any parameter will cause the failure of our app.

Now how we can put these restrictions such as we want the data in a particular type and some are required parameters mandatory to pass and some are optional how we can tell the user if they are missing some parameters without our application crashing?

Here is the answer we have the Flask Extension Flask-Pydantic that will help us to validate the data sent by the user and it will tell the user in the nice formatted message if they are missing some required parameters or type of parameters are not the same as our app is accepting.

## Installation

```plaintext
pip install Flask-Pydantic
```

[Here](https://pypi.org/project/Flask-Pydantic/) is the official doc link of Flask-Pydantic Extension.

## Usage With Example

Suppose we are building blog API with Flask then we have the route that will create a post and the user will send the data in the format such as some required parameters like title, subtitle and content of the blog post of type string and there is one optional parameter like rating of type string it is optional the app will not crash if the user doesn't send the rating. So Here we will create a model name PostBody that will be used to validate the post data sent by the user.

```python
from pydantic import BaseModel
from typing import Optional


class PostBody(BaseModel):
    title: str
    subtitle: str
    content: str
    rating: Optional[str]
```

To define the PostBody, first, we need to import the BaseModel from pydantic then we need to create a class name PostBody that will inherit the BaseModel of pydantic and then in this class, you can define the parameters and its type in code we have three required parameters title, subtitle, the content of type string and one optional parameter rating on type string to define it optional we need to import the optional from tying module.

Now to use this model we need to pass it as a parameter name body to the route of create-post

```python
from flask import Flask
from pydantic import BaseModel
from typing import Optional
from flask_pydantic import validate

app = Flask(__name__)

all_posts = [{"title": "This is first title", "subtitle": "This is the first subtitle", "content": "This is content of the first blog"},]


class PostBody(BaseModel):
    title: str
    subtitle: str
    content: str
    rating: Optional[str]


@app.route("/", methods=["POST"])
@validate()
def create_post(body: PostBody):
    print(body)
    all_posts.append(body.dict())
    return "Success"

if __name__ == "__main__":
    app.run(debug=True)
```

**Code Explanation**

In the route first to validate the post body the user is sending you need the validate method import from flask\_pydantic and simply use validate as a decorator just below the app.route decorator.

Pass the PostBody model as the parameter name body(don't change the name it will cause error).

**Run this file and we will test this API route with the POSTMAN**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673687713466/e91875ba-2437-48a2-9e3c-7d7ae703b4e6.png align="center")

**Output**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673687752254/be99583e-5d1b-4c88-ab86-23519a5f1835.png align="center")

**Defining the Response Model**

Sometimes you want to send the response in a particular format and this is good you can save yourself from sending sensitive information in the response.

**First Define the Response Model**

```python
from pydantic import BaseModel

class PostReponse(BaseModel):
    title: str
    subtitle: str
    content: str
```

Here we created a class name PostResponse and it is inheriting the BaseModel of pydantic

**Use the Response Model in our API**

```python
from flask import Flask
from pydantic import BaseModel
from typing import Optional
from flask_pydantic import validate


app = Flask(__name__)


all_posts = [{"title": "This is first title", "subtitle": "This is the first subtitle", "content": "This is content of the first blog"},
             ]


class PostBody(BaseModel):
    title: str
    subtitle: str
    content: str
    rating: Optional[str]


class PostReponse(BaseModel):
    title: str
    subtitle: str
    content: str

@app.route("/", methods=["POST"])
@validate()
def create_post(body: PostBody):
    print(body)
    all_posts.append(body.dict())
    return PostReponse(
        title=body.title,
        subtitle=body.subtitle,
        content=body.content
    )

if __name__ == "__main__":
    app.run(debug=True)
```

**Code Explanation**

Instead of sending Success here, we are sending the PostResponse object with the fields title, subtitle, and content.

**Testing with POSTMAN**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673688628210/79f7072f-8ea2-4944-a026-d2ea80fc4f5d.png align="center")

**Testing with content field missing**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673688850405/a90834ab-0b6f-4e0d-ba30-ec516137f2d0.png align="center")

**Validating the query parameter**

Suppose you want to get one post with the post\_id then you want to validate if the user is providing post\_id query parameter with the correct type then first, define the PostQuery model

```python
from pydantic import BaseModel

class PostQuery(BaseModel):
    post_id: int
```

Now pass this PostQuery model as a parameter name query in the get\_post method

```python
@app.route('/post')
@validate()
def get_post(query: PostQuery):
    post_id = query.post_id
    requested_post = all_posts[post_id]
    return PostReponse(
        title=requested_post['title'],
        subtitle=requested_post['subtitle'],
        content=requested_post['content']
    )
```

**Testing this API route with POSTMAN**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673689315066/9ef1c4af-d209-414b-89c2-3dc234b5ad58.png align="center")

**Testing For Incorrect id**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673689415094/c43f0559-73b7-459d-80bd-e08fc0453335.png align="center")

**Complete Code**

```python
from flask import Flask
from pydantic import BaseModel
from typing import Optional
from flask_pydantic import validate


app = Flask(__name__)


all_posts = [{"title": "This is first title", "subtitle": "This is the first subtitle", "content": "This is content of the first blog"},
             ]


class PostBody(BaseModel):
    title: str
    subtitle: str
    content: str
    rating: Optional[str]


class PostReponse(BaseModel):
    title: str
    subtitle: str
    content: str


class PostQuery(BaseModel):
    post_id: int


@app.route("/", methods=["POST"])
@validate()
def create_post(body: PostBody):
    print(body)
    all_posts.append(body.dict())
    return PostReponse(
        title=body.title,
        subtitle=body.subtitle,
        content=body.content
    )


@app.route('/post')
@validate()
def get_post(query: PostQuery):
    post_id = query.post_id
    requested_post = all_posts[post_id]
    return PostReponse(
        title=requested_post['title'],
        subtitle=requested_post['subtitle'],
        content=requested_post['content']
    )


if __name__ == "__main__":
    app.run(debug=True)
```

Thanks for Reading.

Open for Feedback.
