In this post, we will learn how to use FastAPI Request Body. We will use Pydantic BaseModel class to create our own class that will act as a request body.

When we need to send some data from client to API, we send it as a request body. In other words, a request body is data sent by client to server. On the other hand, response body is the data the API sends back to the client. APIs always provide some response. However, clients do not need to send request body in every case whatsoever.

Typically, we use HTTP methods such as POST, PUT, DELETE and PATCH to send a request body. POST is the most common method. Technically, we can also use GET method for sending request body in FastAPI. However, the HTTP specification does not support it. Also, the interactive Swagger UI will not show proper documentation for such a case.

In earlier posts, we looked at FastAPI Path Parameters and FastAPI Query Parameters. If you are new to FastAPI, you can first go through those posts to get a better understanding.

1 – FastAPI Request Body

Let us look at an example where we use request body.

from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel

class Book(BaseModel):
    book_name: str
    author_name: str
    genre: Optional[str] = None
    publish_year: Optional[int] = None

app = FastAPI()

@app.post("/books/")
def create_book(book: Book):
    return book

In the above snippet, the first important point is the import statement where we import BaseModel from Pydantic (line 3).

Using the BaseModel, we create our own data model class Book. Basically, the Book class inherits from the BaseModel class. We use standard python types such as str and int for the various attributes.

On similar lines as query parameters, when a model attribute has a default value, it is an optional field. In the Book class, genre and publish_year are optional since we have set a default value of None for them.

Once the class is defined, we use it as a parameter in the request handler function create_book. If a parameter is not present in the path and it also uses Pydantic BaseModel, FastAPI automatically considers it as a request body. FastAPI will read the incoming request payload as JSON and convert the corresponding data types if needed. Also, it will perform validation and return an appropriate error response.

The automatic API documentation will also show the JSON schema belonging to the Book class in the schema section. See below screenshot.

 fastapi request body schema

Also, the same will be available in the specific path operation as below:

fastapi request body path operation

2 – Accessing the Model Attributes

In the previous section, we simply used the model to map the request body. However, we can also access the various attributes of the model within our function.

See below example:

@app.post("/books/")
def create_book(book: Book):
    book_dict = book.dict()
    description = book.book_name + "/**" + book.author_name + "/**" + str(book.publish_year)
    book_dict.update({"description": description})
    return book_dict

Here, we create a description attribute by concatenating the book_name, author_name and publish_year attributes from the Book model. Then, we add the description in book_dict and return the same as response.

3 – Validation of Model Attributes

As discussed earlier, FastAPI also validates the request body against the model we have defined and returns an appropriate error response.

For example, if we do not provide any value for one of the required fields such as author_name and invoke the endpoint, we get the below response.

{
  "detail": [
    {
      "loc": [
        "body",
        "author_name"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

This is accompanied by HTTP error code of 422 i.e. Unprocessable Entity.

4 – Request Body with Path Parameters

We can also declare request body with path parameters. FastAPI will automatically determine which function parameters should be taken from the path.

@app.put("/books/{book_id}")
def update_book(book_id: int, book: Book):
    return {"book_id": book_id, **book.dict()}

Here, book_id is a path parameter. However, book is of type Book model.

Similarly, we can also have a combination of path parameter, query parameter and request body.

Conclusion

With this, we have successfully learnt how to use FastAPI Request Body for our API endpoints. Basically, we leveraged the power of Pydantic BaseModel class to make things easier for us. This provided us automatic conversion and validation of the incoming request.

If you have any comments or queries, please feel free to write in the comments section below.

Categories: BlogFastAPI

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *