Fastapi: [BUG] Body is always parsed as JSON regardless of media_type

Created on 22 Feb 2020  路  15Comments  路  Source: tiangolo/fastapi

Describe the bug

This is to continue the discussion at https://github.com/tiangolo/fastapi/issues/579#issuecomment-589263249. Body accepts an argument media_type, but regardless of the media_type Body is parsed as JSON. This is a problem for other media_types such as plain/text, application/sql, etc. And this is not compliant to OpenAPI content. Body should be able to represent plain text as str too.

Basically I wish I could do this:

request: str = Body(..., media_type='text/plain')

However, this produces 400 parsing error because Body is parsed as JSON anyway.

To Reproduce

  1. Create a file with:
from fastapi import FastAPI, Body

app = FastAPI()

@app.post("/")
def read_root(body: str = Body(..., media_type='text/plain')):
    return {"I received:": body}
  1. Run the server.

  2. Then execute: curl -d 'I want to print this' -H 'Content-Type: plain/text' http://localhost:8000

  3. It returns {"detail":"There was an error parsing the body"}

  4. But I expected it to return {"I received": "I want to print this"}.

Expected behavior

My expectation is that the Body should be parsed based on the Content-Type header always.

Screenshots

I think the information is quite comprehensive without screenshots.

Environment

  • OS: Ubuntu 18.04
  • FastAPI Version: 0.49.0
  • Python 3.7.4

Additional context

The associated part is: https://github.com/tiangolo/fastapi/blob/9c3c9b6e78768374868d690bc05918d58481e880/fastapi/routing.py#L114

This does not check Content-Type. My proposal is to fix it as

if body_bytes and request.headers['Content-Type'] == 'application/json':
# if body_bytes and request.headers.get('Content-Type', 'application/json'): # if the content type should be assumed.
    body = await request.json()
else:
    body = body_bytes

I can make a PR for this, but I would like to learn the maintainers' opinion on this.
@tiangolo @dmontagu @phy25, thanks for the great project!

bug

Most helpful comment

Any update on the fix for this? I'd love to be able to get my API docs to include the request body documentation for text/plain POST endpoints. :)

All 15 comments

Looking forward to this. I have a bunch of raw text (words from files) I want pumping into my api with a simple api as possible..

I have the fix suggested above implemented, and it works in the project that I'm currently developing, but I'm unable to figure out a way to get all of the tests to pass. For example, I'm getting a test failure on tests/test_tutorial/test_body/test_tutorial001.py during test_post_broken_body(). The value of response.status_code is 422, which is causing the assertion of assert response.status_code == expected_status to fail. Any suggestions, anyone?

Oh, that's why I cant have a YAML body in an endpoint...

With @jbkoh's proposal, I get this error in the tests:

fastapi/routing.py:151: error: Incompatible types in assignment (expression has type "bytes", variable has type "Optional[FormData]")
Found 1 error in 1 file (checked 40 source files)

@heitorPB What's the input here?

@jbkoh
This is the output of the scripts/tests.sh with the changes you suggested. I'm running on master branch.

Did you run the tests?

@heitorPB Ah, no I didn't. I was waiting for the maintainers' response before properly implementing the proposed solution. I will try to find some cycles to actually run the test. I guess @jacob-vincent had a similar issue.

If you are sending plain text files, the best way to do it (and the common practice / "standard") is to send them as form data.

Here are the docs for that: https://fastapi.tiangolo.com/tutorial/request-files/

Another option is to read the body directly as a stream by getting the request directly: https://fastapi.tiangolo.com/advanced/using-request-directly/

@jbkoh About the suggested change, I'm not sure yet how it would work and what else would need to interact with it, but maybe you can start a PR and we can see what else could break or what else would be needed for it.

Another option is to read the body directly as a stream by getting the request directly: https://fastapi.tiangolo.com/advanced/using-request-directly/

The downside is that it is not documented in the OpenAPI.json file.

What's the point of the media_type option in Body if it won't be honored.

What's the point of the media_type option in Body if it won't be honored.

@htapal It's currently passed onto openapi generation.

What's the point of the media_type option in Body if it won't be honored.

@htapal It's currently passed onto openapi generation.

What good does that do if the framework doesn't honor the media type of the body? Passing on to the openapi spec is a by product, cherry on top you could say for the functionality provided by the framework. In this case, setting the media_type of the Body correctly sets up the API docs with the interactive docs even customizing the form based on what the resource is declaring is the media type it accepts, however, when posting the data, the framework completely ignores the declare Body media type.

The workaround of using Form or the request directly is not acceptable. Fastapi is a framework to build REST apis and it's a very, very good one. But for it to only expert JSON and form-data as the request body is very short-sighted especially since the Body class allows you to declare the media type.

@jacob-vincent did you had any success to make the tests pass?

Is there any other way to document the request body in OpenAPI documentation, besides Body(...)?

I have a legacy service that I am porting to FastAPI, and one of the operations accepts a YAML body. I am happy to parse it myself using the raw request, but I do not see any way to express that a) this operation accepts a body, or b) that the body should be application/yaml.

Most of the users of my service use the Swagger UI directly, so not being able to enter the body for the request there would be a huge problem for them.

Any update on the fix for this? I'd love to be able to get my API docs to include the request body documentation for text/plain POST endpoints. :)

Was this page helpful?
0 / 5 - 0 ratings