{"id":907,"hash":"de9904059f9893a182b7d4a24a5cc280be75cb5e47a9d9334dd807fcddb78be9","pattern":"Python: FastAPI error 422 with POST request when sending JSON data","full_message":"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 422 Unprocessable Entity error.\n\nHere is the FastAPI code:\n\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n@app.post(\"/\")\ndef main(user):\n    return user\n\nHere is my JavaScript request:\n\nlet axios = require('axios')\n\ndata = { \n    user: 'smith' \n}\n\naxios.post('http://localhost:8000', data)\n    .then(response => (console.log(response.url)))\n\nAlso, using Python requests:\n\nimport requests\n\nurl = 'http://127.0.0.1:8000'\ndata = {'user': 'Smith'}\n\nresponse = requests.post(url, json=data)\nprint(response.text)\n\nI also tried to parse as JSON, enconding using utf-8, and change the headers, but nothing worked for me.","ecosystem":"pypi","package_name":"json","package_version":null,"solution":"A response having a 422 status code (i.e., Unprocessable entity)  will have a response body that specifies the error message, telling exactly which part of your request is missing or doesn’t match the expected format. The code snippet you povided shows that you are trying to post JSON data to an endpoint that is expecting user as a query parameter, rather than JSON payload. Hence, the 422 Unprocessable entity error.\n\nBelow are given various approaches on how to define a FastAPI endpoint that is expecting JSON data. Also, Python and JavaScript HTTP client examples are provided, in order to test the given backend endpoints.\n\nOption 1\nAs per the documentation, when you need to send JSON data from a client (let's say, a browser) to your API, you send it as a request body (through  a POST request). To declare a request body, you can use Pydantic models.\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\nclass Base(BaseModel):\n    user: str\n\napp = FastAPI()\n\n@app.post('/')\nasync def main(base: Base):\n    return base\n\nOption 2\nIf one doesn't want to use Pydantic models, they could also use Body parameters directly defined in the endpoint. If only a single body parameter is defined (as in your example), you could use the special Body parameter embed. On a side note, the ellipsis (...) inside the Body type below is used to indicate that a value is required. To declare parameters as Optional instead, please have a look at this answer.\n\nfrom fastapi import Body\n\n@app.post('/')\nasync def main(user: str = Body(..., embed=True)):\n    return {'user': user}\n\nOption 3\nAnother (less recommended) way would be to use a Dict type (or simply dict in Python 3.9+) to declare a key:value pair. However, in this way, you can't use custom validations for various attributes in your expected JSON, as you would do with Pydantic models or Body fields (e.g., check if an email address is valid, or if a string follows a specific pattern).\n\nfrom typing import Dict, Any\n\n@app.post('/')\nasync def main(payload: Dict[Any, Any]): \n    return payload\n\nIn the example above, payload could also be defined as payload: dict[Any, Any], or simply payload: dict.\n\nPlease note that the solution above would only consider a dictionary object valid, but not a list of dictionary objects. Thus, if one needs to post a list of dict objects, the endpoint should be defined as payload: List[dict] (or payload: list[dict]) and the input data should look like [{\"user1\": \"foo\"}] (for single dict object) or [{\"user1\": \"foo\"},{\"user2\": \"bar\"}] (for multiple dict objects).\n\nOption 4\nIf you are confident that the incoming data is a valid JSON, you can use Starlette's Request object directly to get the request body parsed as JSON, using await request.json(). However, with this approach, not only can't you use custom validations for your attributes, but you would also need to define your endpoint with async def, since request.json() is an async method and thus, one needs to await it. There is, though, an alternative way to keep your endpoint defined with normal def, and have the async method called within an async def dependency (see this answer for more details). For more details on def vs async def, please have  look at this answer.\n\nfrom fastapi import Request\n\n@app.post('/')\nasync def main(request: Request): \n    return await request.json()\n\nIf you wish, you could also implement some checking on the Content-Type request header value, before attempting to parse the data, similar to this answer. However, just because a request says application/json in the Content-Type header, it doesn't always mean that this is true, or  that the incoming data is a valid JSON (e.g., it may be missing a curly bracket or have a key that does not have a value, and so on). Note that according to the latest RFC8259, JSON can take the form of any data type that is valid for inclusion inside JSON, not just arrays or objects. So, for instance, a single string or number would be valid JSON:\n\nA JSON text is a serialized value.  Note that certain previous\nspecifications of JSON constrained a JSON text to be an object or an\narray.  Implementations that generate only objects or arrays where a\nJSON text is called for will be interoperable in the sense that all\nimplementations will accept these as conforming JSON texts.\n\nJSON-text = ws value ws\n\nHence using this approach, you should be aware that the user could pass, for instance, a single number or string instead of dictionary or list of dictionaries and still be considered valid.\n\nFor the validation check, you could use a try-except block when you attempt to parse the data, allowing you to handle a possible JSONDecodeError. Again, if you need the endpoint defined with normal def instead, you could have the validation check below take place inside an async def dependency (see the linked answer earlier).\n\nfrom fastapi import Request, HTTPException\nfrom json import JSONDecodeError\n\n@app.post('/')\nasync def main(request: Request):\n    content_type = request.headers.get('Content-Type')\n    \n    if content_type is None:\n        raise HTTPException(status_code=400, detail='No Content-Type provided')\n    elif content_type == 'application/json':\n        try:\n            return await request.json()\n        except JSONDecodeError:\n            raise HTTPException(status_code=400, detail='Invalid JSON data')\n    else:\n        raise HTTPException(status_code=400, detail='Content-Type not supported')\n\nIf you would like the endpoint accepting both specific/pre-defined and arbitrary JSON data, please check this answer out. Also, note that FastAPI/Starlette uses the standard json library for parsing the data behind the scenes. If one is looking for a faster alternative, please have a look at this answer that demonstrates how to use orjson instead.\n\nTest all the options above\nUsing Python requests library\nRelated answer can be found here.\n\nimport requests\n\nurl = 'http://127.0.0.1:8000/'\npayload ={'user': 'foo'}\nresp = requests.post(url=url, json=payload)\nprint(resp.json())\n\nUsing JavaScript Fetch API\nRelated answers can be found here and here as well. For examples using axios, please have a look at this answer, as well as this answer and this answer.\n\nfetch('/', {\n        method: 'POST',\n        headers: {\n            'Content-Type': 'application/json'\n        },\n        body: JSON.stringify({'user': 'foo'})\n    })\n    .then(resp => resp.json()) // or, resp.text(), etc\n    .then(data => {\n        console.log(data); // handle response data\n    })\n    .catch(error => {\n        console.error(error);\n    });","confidence":0.95,"source":"stackoverflow","source_url":"https://stackoverflow.com/questions/59929028/python-fastapi-error-422-with-post-request-when-sending-json-data","votes":129,"created_at":"2026-04-19T04:51:59.332186+00:00","updated_at":"2026-04-19T04:52:09.112763+00:00"}