0

I'm trying to return a dictionary in FastAPI. I've scoured their site and can't find anything that works. Maybe I'm going about this completely wrong but I would imagine I could pass it a dictionary of results and it would return them as structured in the dictionary? The end goal is to pull this information out of a database but for simplicity and testing I've narrowed it down to this.

from typing import List, Optional
   
from fastapi import FastAPI
from pydantic import BaseModel
    
app = FastAPI()
    
class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []
    
class Items(BaseModel):
    items: List[Item]
    
itemslist = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
   
@app.get("/items", response_model=Items, response_model_exclude_unset=True)
async def read_item(Items: dict):
    return Items(items=itemslist)

When I open the page I get

{
"detail": [
  {
    "loc": [
      "body"
    ],
    "msg": "field required",
    "type": "value_error.missing"
    }
  ]
}

In the console log I see

127.0.0.1:53845 - "GET /items HTTP/1.1" 422 Unprocessable Entity
Paul P
  • 3,346
  • 2
  • 12
  • 26
Dylan Kraklan
  • 11
  • 1
  • 3
  • this might help [python-fastapi-unprocessable-entity-error](https://stackoverflow.com/questions/62384392/python-fastapi-unprocessable-entity-error) – sahasrara62 Aug 29 '21 at 22:53
  • You're requiring your view to have an input parameter: `async def read_item(Items: dict):` but you don't seem to provide one when requesting the path. Anything you give as an argument to the view function should be provided as an input (either from the request or from a dependency). If you expect to just call `/items` without any parameters, remove `Items: dict` from the signature: `async def read_item():` – MatsLindh Aug 30 '21 at 09:47
  • Please have a look at [How to return data in JSON format using FastAPI](https://stackoverflow.com/a/73974946/17865804) – Chris Jul 28 '23 at 04:39

1 Answers1

0

There are a few issues with your code:

  1. When you specify an argument in the function definition for a get endpoint, the argument will be expected to be sent in the body. This is why the error message is showing body in the loc field.
@app.get("/items", response_model=Items, response_model_exclude_unset=True)
async def read_item():
    return Items(items=itemslist)
  1. You've defined itemslist as a dict but you want to convert it to a list. Also, typically, a database adaptor will return a list of rows or something similar. This is why I would change it to something like this:
itemslist = [
    {"name": "Foo", "price": 50.2},
    {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
]

This should probably do it, calling the endpoint should return:

$ curl http://127.0.0.1:8000/items | jq
{
  "items": [
    {
      "name": "Foo",
      "price": 50.2
    },
    {
      "name": "Bar",
      "description": "The bartenders",
      "price": 62,
      "tax": 20.2
    },
    {
      "name": "Baz",
      "description": null,
      "price": 50.2,
      "tax": 10.5,
      "tags": []
    }
  ]
}

Comment

If Items only contains a list of Item, I would suggest keeping it simple and returning List[Item] instead (using pydantic's parse_obj_as):

from pydantic import parse_obj_as

# ...

@app.get("/items", response_model=List[Item], response_model_exclude_unset=True)
async def read_item():
    return parse_obj_as(List[Item], itemslist)

Note, however, that the output is slightly different in this case:

$ curl http://127.0.0.1:8000/items | jq
[
  {
    "name": "Foo",
    "price": 50.2
  },
  {
    "name": "Bar",
    "description": "The bartenders",
    "price": 62,
    "tax": 20.2
  },
  {
    "name": "Baz",
    "description": null,
    "price": 50.2,
    "tax": 10.5,
    "tags": []
  }
]
Paul P
  • 3,346
  • 2
  • 12
  • 26