Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FastAPI: how to read body as any valid json?

I haven't found the docs for that use case. How can I get the request body, ensure it's a valid JSON (any valid JSON, including numbers, string, booleans, and nulls, not only objects and arrays) and get the actual JSON. Using Pydantic forces the JSON to have a specific structure.

like image 481
Alejandro Navas Avatar asked Oct 15 '20 20:10

Alejandro Navas


People also ask

How do I pass JSON body in REST API?

To post JSON to a REST API endpoint, you must send an HTTP POST request to the REST API server and provide JSON data in the body of the POST message. You also need to specify the data type in the body of the POST message using the Content-Type: application/json request header.

What is considered valid JSON?

JSON can actually take the form of any data type that is valid for inclusion inside JSON, not just arrays or objects. So for example, a single string or number would be valid JSON. Unlike in JavaScript code in which object properties may be unquoted, in JSON only quoted strings may be used as properties.

How to use fastapi request body?

In this post, we will learn how to use FastAPI Request Body. We will use Pydantic BaseModel class to create our own class that will act as a request body. When we need to send some data from client to API, we send it as a request body. In other words, a request body is data sent by client to server.

How do I check if a JSON request is valid?

Read the body of the request as JSON. Convert the corresponding types (if needed). Validate the data. If the data is invalid, it will return a nice and clear error, indicating exactly where and what was the incorrect data. Give you the received data in the parameter item.

How does fastapi work in Python?

In FastAPI, you derive from BaseModel to describe the data models you send and receive (i.e. FastAPI also parses for you from a body and translates to Python objects). Also, it relies on the modeling and processing from pydantic.

How does fastapi know the value of Q is not required?

FastAPI will know that the value of q is not required because of the default value = None. The Union in Union [str, None] is not used by FastAPI, but will allow your editor to give you better support and detect errors. If you don't want to use Pydantic models, you can also use Body parameters.


Video Answer


4 Answers

You can find nearly everything inside the Request object

You are able to get request body with request.json(), which will give you the parsed JSON as dictionary.

from fastapi import Request, FastAPI

@app.post("/dummypath")
async def get_body(request: Request):
    return await request.json()

If you want access the body as string, you can use request.body()

like image 153
Yagiz Degirmenci Avatar answered Oct 24 '22 04:10

Yagiz Degirmenci


The accepted answer is valid as well, but FastAPI provides a built-in way to do that - check the Singular values in body section in docs.

A parameter with the default Body gets all the payload that doesn't match passed Pydantic-typed parameters (the whole payload in our case) and converts it to the dict. In case of invalid JSON, a standard validation error would be produced.

from fastapi import Body, FastAPI

app = FastAPI()


@app.post('/test')
async def update_item(
        payload: dict = Body(...)
):
    return payload

UPD: Note on ... (Ellipsis) - it allows marking a value as required. Read more in the Required with Ellipsis docs section

like image 37
Oleh Rybalchenko Avatar answered Oct 24 '22 05:10

Oleh Rybalchenko


If you are confident that the incoming data is "a valid JSON", you can create a simple type annotation structure to receive the arbitrary JSON data.

from fastapi import FastAPI
from typing import Any, Dict, AnyStr, List, Union

app = FastAPI()

JSONObject = Dict[AnyStr, Any]
JSONArray = List[Any]
JSONStructure = Union[JSONArray, JSONObject]


@app.post("/")
async def root(arbitrary_json: JSONStructure = None):
    return {"received_data": arbitrary_json}

Examples

1. JSON object

curl -X POST "http://0.0.0.0:6022/" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{\"test_key\":\"test_val\"}"

Response:

{
  "received_data": {
    "test_key": "test_val"
  }
}

2. JSON array

curl -X POST "http://0.0.0.0:6022/" -H  "accept: application/json" -H  "Content-Type: application/json" -d "[\"foo\",\"bar\"]"

Response:

{
  "received_data": [
    "foo",
    "bar"
  ]
}

If you are not sure about the content type of the incoming data, better to parse the request body.

It can be done as,

from fastapi import FastAPI, Request

app = FastAPI()


@app.post("/")
async def root(request: Request):
    return {"received_request_body": await request.body()}

The advantage of this method is that the body will contain any kind of data, JSON, form-data, multipart-form-data, etc.

like image 18
JPG Avatar answered Oct 24 '22 03:10

JPG


from fastapi import Request

async def synonyms__select(request: Request):
    return await request.json()

will return a JSON object.

like image 4
ghchoi Avatar answered Oct 24 '22 03:10

ghchoi