FastAPI POST request with List input raises 422 Unprocessable Entity error

Question:

Hi I am newbie in FastAPI and want to write a POST request in which an input parameter is a list, but I got error 422 unprocessable entity:

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

my POST request is:

@router.post('',status_code=200)
def register(reg_id: int, reg_name: str, reg_option_list:List[int]):
    reg_item = My_DB(
        id=reg_id,
        name=reg_name,
        option_list=reg_option_list,
    )
    item = db.query(My_DB).filter(My_DB.id == service_id).first()

    if item is not None:
        raise HTTPException(status_code=400, detail="Item exists.")
    db.add(reg_item)
    db.commit()
    return reg_item

But when I change my code like below, remove list input and set the value in code as a list, everything works fine:

@router.post('',status_code=200)
def register(reg_id: int, reg_name: str,):
    reg_item = My_DB(
        id=reg_id,
        name=reg_name,
        option_list=[1,2,3],
    )
    item = db.query(My_DB).filter(My_DB.id == service_id).first()

    if item is not None:
        raise HTTPException(status_code=400, detail="Item exists.")
    db.add(reg_item)
    db.commit()
    return reg_item

I will appreciate any help about my list input parameter. Thanks.

Asked By: Saha

||

Answers:

As per the documentation (have a look at the "Tip" section)

To declare a query parameter with a type of list, like in the example
above, you need to explicitly use Query, otherwise it would be
interpreted as a request body.

Thus, by declaring a List parameter in the way you do, the endpoint will expect to receive it as body, rather than query, parameter. Hence, the 422 unprocessable entity error with the specific details you provided (i.e., body field is missing). You could also check that through OpenAPI/Swagger UI at, for instance, http://127.0.0.1:8000/docs. You would see that the value for reg_option_list is expected to be passed to the Request body section.

The way to do this is to define the query parameter explicitly with Query, allowing thus the parameter to appear multiple times in the URL. Example below:

from fastapi import Query

@router.post('/')
def register(reg_id: int, reg_name: str, reg_option_list: List[int] = Query(...)):
    # ...

Sample URL query string:

?reg_id=1&reg_name=foo&reg_option_list=1&reg_option_list=2&reg_option_list=3
Answered By: Chris

You can use Query in default type

from typing import List

from fastapi import FastAPI, Query

app = FastAPI()
@app.get("/items/")
def read_items(q: List[int] = Query(None)):
    return {"q": q}
Answered By: maral7495