Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast API : How to return a str as JSON [duplicate]

Tags:

python

fastapi

In python, using Fast API, I have a str that when print show (this is an example, the real str is more complex) :

[1592494390, 'test', -0.2761097089544078, -0.0852381808812182, -0.101153, nan]

I want to return this using Fast API as a JSON array.

Using JSONResponse

def get_json(dataset: str, timeseries: str):

    test = "[1592494390, 'test', -0.2761097089544078, -0.0852381808812182, -0.101153, nan]"
    print(test)
    return JSONResponse(content=test)

The print is as expecting showing:

[1592494390, 'test', -0.2761097089544078, -0.0852381808812182, -0.101153, nan]

But the answer of the API when hitting the call is:

"[1592494390, 'test', -0.2761097089544078, -0.0852381808812182, -0.101153, nan]"

So my str is being serialised again and I don't know how to by-pass that.

Using Response :

The documentation of Fast API includes a page that describes how to return a Response directly (https://fastapi.tiangolo.com/advanced/response-directly/) where it is written:

When you return a Response directly its data is not validated, converted (serialized), nor documented automatically.

But using this method leads to an error :

def get_json(dataset: str, timeseries: str):

    test = "[1592494390, 'test', -0.2761097089544078, -0.0852381808812182, -0.101153, nan]"
    print(test)
    return Response(content=test, media_type="application/json")
> line 53, in get_json
    return Response(content=test, media_type="application/json")
  File "pydantic/main.py", line 331, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 2 validation errors for Response
description
  field required (type=value_error.missing)
content
  value is not a valid dict (type=type_error.dict)

By the way the exact xml example of the documentation gives the same error:

> line 61, in get_json
    return Response(content=data, media_type="application/xml")
  File "pydantic/main.py", line 331, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 2 validation errors for Response
description
  field required (type=value_error.missing)
content
  value is not a valid dict (type=type_error.dict)

I know I can convert my data to a an array or dict to be serialized I how want but as I already have the right str and don't want the job to be done several times.

like image 628
bloub Avatar asked Dec 10 '25 21:12

bloub


2 Answers

I investigated as it was strange that the Fast API example didn't work.

The problem was that I was not using the right Response class.

So I had to import the right class to get things working as expected :

from fastapi import Response

The issue might be the same while trying with JSONResponse.

The following code is then answering the problem :

from fastapi import Response



def get_json(dataset: str, timeseries: str):

test = "[1592494390, 'test', -0.2761097089544078, -0.0852381808812182, -0.101153, nan]"
print(test)
return Response(content=test, media_type="application/json")
like image 121
bloub Avatar answered Dec 13 '25 10:12

bloub


As per FastAPI's docs:

When you create a FastAPI path operation you can normally return any data from it: a dict, a list, a Pydantic model, a database model, etc.

By default, FastAPI would automatically convert that return value to JSON using the jsonable_encoder

This means, when you return a string, it will be converted into a JSON string.

One way to verify this is by curling your endpoint and piping the result into jq.

Generally, you should leave the serialisation to FastAPI which is doing a great job at it.

On top of that, nan (not a number) is not part of the JSON standard

My suggestion is to make sure that the data that is supposed to be returned is a list or a dict, e.g.:

from fastapi import FastAPI

app = FastAPI()

@app.get("/get-json")
async def get_json():
    test = [
        1592494390,
       "test",
       -0.2761097089544078,
       -0.0852381808812182,
       -0.101153,
       None,
    ]
    return test
    # You could be explicit here and return a JSONResponse.
    # return JSONResponse(content=test)

Now, here's what this endpoint returns:

curl localhost:8080/get-json | jq type
"array"

If you run this command on your endpoint, it will probably show a "string" instead of "array".

If your data is already serialised and you cannot get the original data directly, I would go with one of the suggested methods and deserialise it first.

However, in that case, you would have to escape all double quotes properly and replace the nan with something that JSON understands (e.g. null):

import json
...
@app.get("/get-json")
async def get_json():
    test = "[1592494390, \"test\", -0.2761097089544078, -0.0852381808812182, -0.101153, null]"
#                        ^^    ^^                                                       ^^^^
#                    need to be escaped                                             cannot be nan

    return json.loads(test)

Now, this endpoint returns:

curl localhost:8080/get-json | jq type
"array"
like image 30
Paul P Avatar answered Dec 13 '25 10:12

Paul P



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!