Masterstack8080
Masterstack8080

Reputation: 517

FastAPI - Postman error 422 Unprocessable Entity

I am using FastAPI to make get/post/put/del requests, which all work perfectly fine in the browser. I wanted to use Postman to do the exact same thing; however, I am running into an issue trying to do anything other than GET. Below is the error I am getting:

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

422 Unprocessable Entity is the exact error.

enter image description here

Below is the code I am using:

from lib2to3.pytree import Base
from fastapi import FastAPI, Path, Query, HTTPException, status, File, Form
from typing import Optional, Dict, Type
from pydantic import BaseModel
import inspect

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float
    brand: Optional[str] = None


class UpdateItem(BaseModel):
    name: Optional[str] = None
    price: Optional[float] = None
    brand: Optional[str] = None


inventory = {}

@app.get("/get-item/{item_id}")
def get_item(item_id: int = Path(None, description = "The ID of the item")):
    if item_id not in inventory:
        raise HTTPException(status_code = 404, detail = "Item ID not found")
    return inventory[item_id]
    

@app.get("/get-by-name/")
def get_item(name: str = Query(None, title = "Name", description = "Test")):
    for item_id in inventory:
        if inventory[item_id].name == name:
            return inventory[item_id]
    # return {"Data": "Not found"}
    raise HTTPException(status_code = 404, detail = "Item ID not found")


@app.post("/create-item/{item_id}")
def create_item(item_id: int, item: Item):
    if item_id in inventory:
        raise HTTPException(status_code = 400, detail = "Item ID already exists")

    inventory[item_id] = item
    print(type(item))
    return inventory[item_id]
    

@app.put("/update-item/{item_id}")
def update_item(item_id: int, item: UpdateItem):
    if item_id not in inventory:
        # return {"Error": "Item does not exist"}
        raise HTTPException(status_code = 404, detail = "Item ID not found")

    if item.name != None:
        inventory[item_id].name = item.name
    if item.brand != None:
        inventory[item_id].brand = item.brand
    if item.price != None:
        inventory[item_id].price = item.price
    
    return inventory[item_id]


@app.delete("/delete-item/{item_id}")
def delete_item(item_id: int = Query(..., description="ID of item you want to delete", ge=0)):
    if item_id not in inventory:
        # return {"Error": "ID does not exist"}
        raise HTTPException(status_code = 404, detail = "Item ID not found")
    del inventory[item_id]
    return {"Success": "Item deleted"}

I tried this possible solution with no luck: https://github.com/tiangolo/fastapi/issues/2387

Upvotes: 1

Views: 10579

Answers (3)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626870

In my case, since I was passing a parameter as fastapi.Form(), all I needed was to send it via Body > form-data.

When you POST, you should not use explicit params after ? in the URL. So, you need to define your method like

from fastapi import Form

# ...

@app.post("/create-item")                           # NOTE {item_id} is REMOVED!
def create_item(item_id: int = Form(), item: Item): # NOTE: item_id: int = Form()
    if item_id in inventory:
        raise HTTPException(status_code = 400, detail = "Item ID already exists")

    inventory[item_id] = item
    print(type(item))
    return inventory[item_id]

And then

enter image description here

Upvotes: 0

On postman you need to change headers, by default, the value of Content-Type is plain/text, change it to application/json. View answer at POST request response 422 error {'detail': [{'loc': ['body'], 'msg': 'value is not a valid dict', 'type': 'type_error.dict'}]}

Upvotes: 1

Chris
Chris

Reputation: 34199

Your endpoint expects Item as JSON (body) data, but the screenshot you provided shows that you are sending the required fields as Query parameters (using the Params tab in Postman); hence, the error that the body is missing. You should instead add your data to the body of your POST request in Postman. To do that, you should go to Body > raw, and select JSON from the dropdown list to indicate the format of your data. Your payload should look something like this:

{
 "name": "foo",
 "price": 1.50
}

See related answers here and here as well. In case you needed to pass the parameters of Item model as Query parameters, you should then use Depends(), as described in this answer (Method 2).

Upvotes: 1

Related Questions