6

I need to create an endpoint that can receive the following JSON and recognize the objects contained in it:

{​
  "data": [
    {​
      "start": "A", "end": "B", "distance": 6
    }​,
    {​
      "start": "A", "end": "E", "distance": 4
    }​
  ]
}

I created a model to handle a single object:

class GraphBase(BaseModel):
    start: str
    end: str
    distance: int

And with it, I could save it in a database. But now I need to receive a list of objects and save them all. I tried to do something like this:

class GraphList(BaseModel):
    data: Dict[str, List[GraphBase]]

@app.post("/dummypath")
async def get_body(data: schemas.GraphList):
    return data

But I keep getting this error on FastApi: Error getting request body: Expecting property name enclosed in double quotes: line 1 column 2 (char 1) and this message on the response:

{
    "detail": "There was an error parsing the body"
}

I'm new to python and even newer to FastApi, how can I transform that JSON to a list of GraphBaseto save them in my db?

Richard Wilson
  • 297
  • 4
  • 17
Reissel Reis
  • 63
  • 1
  • 1
  • 4

2 Answers2

9

This is a working example.

from typing import List
from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()

class GraphBase(BaseModel):
    start: str
    end: str
    distance: int

class GraphList(BaseModel):
    data: List[GraphBase]

@app.post("/dummypath")
async def get_body(data: GraphList):
    return data

I could try this API on the autogenerated docs.

enter image description here

Or, on the console (you may need to adjust the URL depending on your setting):

curl -X 'POST' \
  'http://localhost:8000/dummypath' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "data": [
    {
      "start": "string",
      "end": "string",
      "distance": 0
    }
  ]
}'

The error looks like the data problem. And I found that you have extra spaces at several places. Try the following:

{
  "data": [
    {
      "start": "A", "end": "B", "distance": 6
    },
    {
      "start": "A", "end": "E", "distance": 4
    }
  ]
}

The positions of extra spaces (which I removed) are below:

enter image description here

Kota Mori
  • 6,510
  • 1
  • 21
  • 25
  • Thank you so much!! I spent a lot of time looking for a problem in the code that was in the data!! It worked with your formatted data. What did you use to locate those extra whitespaces? And do you know if FastApi has a way to handle this kind of problem? – Reissel Reis Aug 04 '21 at 14:52
  • I used https://jsoneditoronline.org/. The original data was invalid there. FastAPI won't help you because the data was not a valid JSON object. The best it could do is to tell you that the parsing data failed, which actually was in the error message. – Kota Mori Aug 04 '21 at 23:38
  • Yeah, I realized that something could be wrong with the data, but couldn't figure out what it was. All editors I used were unable to show those extra spaces and the error message was unclear of what was the issue. Again, thank you for the explanation and the link to the json validator you used!!! – Reissel Reis Aug 06 '21 at 15:08
  • whilst that will work with json content type , it wont work with formdata content type – Jimmy Obonyo Abor May 16 '22 at 22:10
  • thanks! how do we specify minimum and maximum (or fixed) length of the list expected, for validation? – Nikhil VJ Apr 01 '23 at 07:40
0

Generally, FastAPI allows for simply receiving a list of objects, there's no need to wrap that list in an extra object.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class ObjectListItem(BaseModel):
  ...

@app.post("/api_route")
def receive_list_of_objects(objects_list: list[ObjectListItem]):
  ...

More information in the FastAPI documentation.

verwirrt
  • 125
  • 1
  • 9
  • Assuming I need to post something really simple, like a list of integers, would the `objects_list` passed via the post request simply be a JSON list : [1,2,3] ? – Derek Jul 31 '23 at 05:03
  • There's an example of handling lists of primitive values (e.g. int, str) here: https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#query-parameter-list-multiple-values To pass it in the request body, you need to declare a Pydantic model for it: https://fastapi.tiangolo.com/tutorial/body/ – verwirrt Jul 31 '23 at 15:54