Getting the Request Body in FastAPI

Updated: March 19, 2023 By: Goodman Post a comment

In POST requests, values are sent in the body of the request. When the client side wants to upload files or images, they are most likely sent with a media type of multipart/form-data or application/x-www-form-urlencoded.

In FastAPI, parsing data from the request body works almost the same as query parameters except for one crucial thing is that you always have to use the Body function (don’t forget to import it from fastapi, otherwise you will receive an error). Let’s examine the minimal example below for more clarity:

from fastapi import FastAPI, Body

app = FastAPI()

@app.post('/products', status_code=201)
async def add_product(name: str = Body(...), price: float = Body(...)):
    return {"message": f"Product {name} with the price {price} has been added successfully."}

Launch our API:

uvicorn main:app --reload

Now use an HTTP client like Postman, Thunder Client, or whatsoever to test our work. Make a POST request with the following JSON body to http://localhost:8000:

{
  "name": "Blue Sling",
  "price": 99.99
}

And you will get this response:

{
  "message": "Product Blue Sling with the price 99.99 has been added successfully."
}

The status code is 201 (Created).

Using Pydantic Models

We can define pydantic models and use them as type hints in our path arguments. By doing so, FastAPI will automatically instantiate a model instance and validate the data of incoming requests.

Let’s rewrite the example above as follows:

from fastapi import FastAPI, Body
from pydantic import BaseModel

app = FastAPI()

class Product(BaseModel):
    name: str
    price: float


@app.post('/products', status_code=201)
async def add_product(product: Product = Body(..., embed=True), status_code=201):
    return {"message": f"Product {product.name} with the price {product.price} has been added successfully."}

Now send a POST request to our API with the following body:

{
  "product": {
    "name": "Blue Sling",
    "price": 99.99
  }
}

The response should look like this (with the status code 201):

{
  "message": "Product Blue Sling with the price 99.99 has been added successfully."
}

If the input data is invalid (such as the type of price is string or a field is missing like this:

{
  "product": {
    "name": "Blue Sling",
    "price": "abc"
  }
}

We’ll end up with the error 422 Unprocessable Entity:

{
  "detail": [
    {
      "loc": [
        "body",
        "product",
        "price"
      ],
      "msg": "value is not a valid float",
      "type": "type_error.float"
    }
  ]
}

If you go to http://localhost:8000/docs, you’ll have a detailed explanation of the API:

That’s it. Happy coding!