10

I have a POST FastAPI method. I do not want to construct a class nor query string. So, I decide to apply Body() method.

@app.post("/test-single-int")
async def test_single_int(
    t: int = Body(...)
):
    pass

This is the request

POST http://localhost:8000/test-single-int/

{
  "t": 10
}

And this is the response

HTTP/1.1 422 Unprocessable Entity
date: Fri, 22 May 2020 10:00:16 GMT
server: uvicorn
content-length: 83
content-type: application/json
connection: close

{
  "detail": [
    {
      "loc": [
        "body",
        "s"
      ],
      "msg": "str type expected",
      "type": "type_error.str"
    }
  ]
}

However, after trying with many samples, I found that they will not error if I have more than one Body(). For example,

@app.post("/test-multi-mix")
async def test_multi_param(
    s: str = Body(...),
    t: int = Body(...),
):
    pass

Request

POST http://localhost:8000/test-multi-mix/

{
  "s": "test",
  "t": 10
}

Response

HTTP/1.1 200 OK
date: Fri, 22 May 2020 10:16:12 GMT
server: uvicorn
content-length: 4
content-type: application/json
connection: close

null

Does anyone have any idea about my implementation? Are there wrong? Is it not best practice? Or it is a bug?

2 Answers 2

15

It is not a bug, it is how Body behaves, it exists for "extending" request params how documentation outlines:

class Item(BaseModel):
    name: str

class User(BaseModel):
    username: str
    full_name: str = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item,
    user: User,
    importance: int = Body(..., gt=0),
    q: str = None
):
    pass

Valid request body for this view would be:

{
    "item": {
        "name": "Foo",
        "tax": 3.2
    },
    "user": {
        "username": "dave",
        "full_name": "Dave Grohl"
    },
    "importance": 5
}

If you really want to use Body alone you must specify embed=True, this one works as expected:

@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id:int,
    importance: int = Body(..., gt=0, embed=True),
    q: str = None
):
    pass
Sign up to request clarification or add additional context in comments.

1 Comment

I don't really understand why Body behaves like that by default. Do you have a good example of why they made that the default behaviour?
-3

To get any data from body with FastApi:

@app.post("/someurl")
async def someMethod(body: dict):
    return body

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.