Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request with Forms and Files requires the 'File' parameter to be listed first #4384

Closed
9 tasks done
AKlaus opened this issue Jan 7, 2022 · 7 comments
Closed
9 tasks done
Labels
question Question or problem question-migrate

Comments

@AKlaus
Copy link

AKlaus commented Jan 7, 2022

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

@app.post( '/test-fail')
def test( param1: str = Form(...),	# It fails if the File goes first
          file: bytes = File(...)
        ):
    return Response(content=file, media_type="application/octet-stream")

@app.post( '/test-success')
def test( file: bytes = File(...),	# It succeeds if the File goes first 
          param1: str = Form(...)
        ):
    return Response(content=file, media_type="application/octet-stream")

Description

BUG
The File parameter on the POST method must go first, before other Form parameters. Otherwise the end-point returns HTTP code 422.

Details
A command line like below for the end-points from the example

curl --location --request POST 'http://127.0.0.1:5001/test' --form 'param1="fff"' --form 'file=@"file.png"'

would return HTTP code 200 with an expected result for /test-success and HTTP code 422 for /test-fail with the following JSON:

{"detail":[{"loc":["body","file"],"msg":"byte type expected","type":"type_error.bytes"}]}

Expected behaviour
Validation of parameters doesn't depend on the order of the parameters

Operating System

macOS

Operating System Details

v12.0.1

FastAPI Version

0.70.1

Python Version

3.7.10

Additional Context

No response

@AKlaus AKlaus added the question Question or problem label Jan 7, 2022
@harunyasar
Copy link

harunyasar commented Jan 9, 2022

If I don't misunderstand of course, I don't quite agree with you that this is a bug. I think it was a design decision enforced by HTTP protocol. When you pass either File or UploadFile parameter, FastAPI treats like it is a multipart/form-data which means it accepts the following argument — the file (uploaded one) argument, as part of the form. When you pass Form as a first argument FastAPI treats it as an application/x-www-form-urlencoded media type which means it doesn't have a file. So, you should send your file parameter as a string in your failed case. Form more information you can have a look at this page's Technical Details section.

@AKlaus
Copy link
Author

AKlaus commented Jan 10, 2022

I think, @harunyasar misunderstood the problem, as in both cases it's multipart/form-data. The only difference between working and failing is the order of the parameters in the Python method.

@harunyasar
Copy link

Oh I see. It might be a Swagger UI bug. I think this way because FastAPI expects it to be an application/x-www-form-urlencoded even though you are sending it as multipart/form-data with Swagger UI. If you send the test-fail endpoint as Body->x-www-form-urlencoded with Postman, you will see it works. Maybe I'm thinking wrong, I don't know. Let's wait for someone else to join the conversation. Sorry about that.

@AKlaus
Copy link
Author

AKlaus commented Jan 11, 2022

@harunyasar, it can't be a Swagger UI bug, as in my example I'm using curl command (also you can use Postman) to ensure I send the exact same request to the back-end.

@harunyasar
Copy link

harunyasar commented Jan 11, 2022

@AKlaus I know what you are saying but what I am saying is that I suspect Swagger UI shows the Content-Type multipart/form-data incorrectly instead of x-www-form-urlencoded. I am suggesting here you send -H "Content-Type: application/x-www-form-urlencoded" with curl.

curl -X POST http://127.0.0.1:8000/test-fail -H "Content-Type: application/x-www-form-urlencoded" -d "param1=value1&file=value2"

My theory is that there should be something wrong with Swagger UI. Anyway. If someone comes along and gives the correct explanation, I'll be glad to learn something new about FastAPI as well.

@harunyasar
Copy link

Apparently, I am mistaken.

#1964

@AKlaus
Copy link
Author

AKlaus commented Jan 11, 2022

Closing as a duplicate of #1964.

Thank you @harunyasar for pointing out to that ticket! (I question my searching skills)

@AKlaus AKlaus closed this as completed Jan 11, 2022
@tiangolo tiangolo reopened this Feb 27, 2023
Repository owner locked and limited conversation to collaborators Feb 27, 2023
@tiangolo tiangolo converted this issue into discussion #6490 Feb 27, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Question or problem question-migrate
Projects
None yet
Development

No branches or pull requests

3 participants