1

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.

Paul P
  • 3,346
  • 2
  • 12
  • 26
bloub
  • 510
  • 1
  • 4
  • 21

2 Answers2

4

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")
bloub
  • 510
  • 1
  • 4
  • 21
0

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"
Paul P
  • 3,346
  • 2
  • 12
  • 26