How to read the request body using orjson library in FastAPI?

Question:

I am writing code to receive a JSON payload in FastAPI.

Here is my code:

from fastapi import FastAPI, status, Request
from fastapi.responses import ORJSONResponse
import uvicorn
import asyncio
import orjson

app = FastAPI()

@app.post("/", status_code = status.HTTP_200_OK)
async def get_data(request: Request):
    param = await request.json()
    return param

However, what I want is request.json() to be used with orjson instead of the default json library of Python.
Any idea how to address this problem? Please help me, thanks.

Asked By: Nguyen

||

Answers:

Reading request data using orjson

When calling await request.json(), FastAPI (actually Starlette) first reads the body (using the .body() method of the Request object), and then calls json.loads() (using the standard json library of Python) to return a dict/list object to you inside the endpoint (see the implementation here)—it doesn’t use .dumps(), as you mentioned in the comments section, as that method is used to serialise a Python object into JSON.

Hence, to read/convert the request body using orjson instead, you can use the below (if you would like to retrieve the raw body within a def instead of async def endpoint, please have a look at this answer):

from fastapi import FastAPI, Request
import orjson

app = FastAPI()

@app.post('/')
async def submit(request: Request):
    body = await request.body()
    data = orjson.loads(body)
    return 'success'

Returning response data using orjson

When returning data such as dict, list, etc, FastAPI will automatically convert that return value into JSON, using the Python standard json.dumps(), after inspecting every item inside and making sure it is serializable with JSON, using the JSON Compatible Encoder (see this answer for more details). Hence, if you would like to use the orjson library instead, you would need to send a custom Response directly, as described in this answer. Example:

from fastapi import FastAPI, Request
import orjson

app = FastAPI()

@app.post('/')
async def submit(request: Request):
    body = await request.body()
    data = orjson.loads(body)
    return Response(orjson.dumps(data), media_type='application/json')

Alternatively, you can use the ORJSONResponse provided by FastAPI (still make sure you have the orjson libray installed, as well as the content that you are returning is serializable with JSON). Have a look at futher documentation here and here on how to customise and/or set ORJSONResponse as the default response class (the implementation of ORJSONResponse can be found here). Example:

from fastapi import FastAPI, Request
from fastapi.responses import ORJSONResponse
import orjson

app = FastAPI()

@app.post('/', response_class=ORJSONResponse)
async def submit(request: Request):
    body = await request.body()
    data = orjson.loads(body)
    return ORJSONResponse(data)

Please make sure to have a look here, here, as well as here and here to learn about the various approaches of sending JSON data to a FastAPI backend, and how to define an endpoint to expect and validate JSON data, instead of relying on using await request.json() (which is useful when the app requires passing arbitrary JSON data, but does not perform any validation on the data).

Answered By: Chris
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.