'Python: FastAPI error 422 with post request

I'm building a simple API to test a database. When I use get request everything works fine, but if I change to post I get "unprocessable entity" error:

Here is the FastAPI code:

from fastapi import FastAPI

app = FastAPI()

@app.post("/")
def main(user):
    return user

Then, my request using javascript

let axios = require('axios')

data = { 
    user: 'smith' 
}

axios.post('http://localhost:8000', data)
    .then(response => (console.log(response.url)))

Also using Python

import requests

url = 'http://127.0.0.1:8000'
data = {'user': 'Smith'}

response = requests.post(url, json=data)
print(response.text)

I also try to parse as json, enconding using utf-8, and change the headers. Nothing has worked for me.



Solution 1:[1]

Straight from the documentation:

The function parameters will be recognized as follows:

  • If the parameter is also declared in the path, it will be used as a path parameter.
  • If the parameter is of a singular type (like int, float, str, bool, etc) it will be interpreted as a query parameter.
  • If the parameter is declared to be of the type of a Pydantic model, it will be interpreted as a request body."

So to create a POST endpoint that receives a body with a user field you would do something like:

from fastapi import FastAPI
from pydantic import BaseModel


app = FastAPI()


class Data(BaseModel):
    user: str


@app.post("/")
def main(data: Data):
    return data

Solution 2:[2]

In my case, I was calling the python API from different python project like this

queryResponse = requests.post(URL, data= query)

I was using the data property, I changed it to json, then it worked for me

queryResponse = requests.post(URL, json = query)

Solution 3:[3]

If you're using the fetch API and still getting the 422 Unprocessable Entity, ensure that you have set the Content-Type header:

fetch(someURL, {
  method: "POST",
  headers: {
    "Content-type": "application/json"
  },
  body
}).then(...)

This solved the issue in my case. On the server-side I'm using Pydantic models, so if you aren't using those, see the above answers.

Solution 4:[4]

For POST Requests for taking in the request body, you need to do as follows

Create a Pydantic Base Model User

from pydantic import BaseModel

class User(BaseModel):
    user_name: str


@app.post("/")
def main(user: User):
   return user

Solution 5:[5]

FastAPI is based on Python type hints so when you pass a query parameter it accepts key:value pair you need to declare it somehow.

Even something like this will work

from typing import Dict, Any
...
@app.post("/")
def main(user: Dict[Any, Any] = None):
    return user

Out: {"user":"Smith"}

But using Pydantic way more effective

class User(BaseModel):
    user: str

@app.post("/")
def main(user: User):
    return user

Out: {"user":"Smith"}

Solution 6:[6]

The answer posted here is correct. Pydantic models are supposed to be used when it comes to JSON post requests (regarding Form data though, please have a look here). However, if one doesn't want to use Pydantic models, they could also use Body parameters. If a single body parameter is used (as in your example), you can use the special Body parameter embed. Below is a working example.

app.py

import uvicorn
from fastapi import Body, FastAPI

app = FastAPI()

@app.post("/")
async def main(user: str = Body(..., embed=True)):
    return {"user": user}
    
if __name__ == '__main__':
    uvicorn.run(app, host='127.0.0.1', port=8000, debug=True)

test.py

import requests

url = 'http://127.0.0.1:8000'
payload ={"user": "foo"}
resp = requests.post(url=url, json=payload)
print(resp.json())

Solution 7:[7]

In my case, my FastAPI endpoint is expecting form-data instead of JSON. Thus, the fix is to send form data instead of JSON. (Note: for node-js, FormData is not available and form-data can be used)

Solution 8:[8]

(if not syntax error like above) There could be many reasons for receiving a response 422 from a post request.

One can replicate this by:

  • editing your body structure
  • changing the type of your body (Send any string)
  • changing/removing your header content type

How I usually debug this is as follows:

  1. If you are using FastAPI, test on the local host using the built-in, '/docs' route, if a post fails there, it's likely a syntax/logic error and not related to your post route. This feature of FastAPI is very helpfully. Note Post requests don't need/expect headers on the UI since it gives you a text place to fill it in.

  2. Test is on a variable body endpoint: you can set this up like:

@app.post('/test')
async def function(objectName: dict = Body(...)):

Send a request with any JSON, if you still receive 422, then move to next.

  1. Make sure your header content type is correct, the most common is just:
headers = {'Content-Type': 'application/json'};

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 michaeloliver
Solution 2 Sunil Garg
Solution 3
Solution 4 Avinash Ravi
Solution 5 Krishna
Solution 6
Solution 7 Yong
Solution 8 Jorangutang