'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:
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.
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.
- 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 |