3

I am sending and image and also json data to my API in the following way:

import requests
filename = "test_image.jpeg"
files = {'my_file': (filename, open(filename, 'rb'))}
json={'first': "Hello", 'second': "World"}

response = requests.post('http://127.0.0.1:8000/file', files=files, params=json)

How do I receive both the image and json data on the server-side via FastAPI?

My code looks like this:

@app.post('/file')
def _file_upload(my_file: UploadFile = File(...), params: str = Form(...)):

    image_bytes = my_file.file.read()
    decoded = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), -1)
    pg_image = cv2.resize(decoded, (220, 220))
    return {"file_size": params}

However, this gives me the following error:

<Response [422]>
{'detail': [{'loc': ['body', 'params'], 'msg': 'field required', 'type': 'value_error.missing'}]}

Is there something which I am doing wrong here?

0

3 Answers 3

6

You must define the args that you are expecting in the router function as,

# app.py
from fastapi import FastAPI, File, UploadFile, Form

app = FastAPI()


@app.post('/file')
def _file_upload(
        my_file: UploadFile = File(...),
        first: str = Form(...),
        second: str = Form("default value  for second"),
):
    return {
        "name": my_file.filename,
        "first": first,
        "second": second
    }
# client.py
import requests

filename = "requirements.txt"
files = {'my_file': (filename, open(filename, 'rb'))}
json = {'first': "Hello", 'second': "World"}

response = requests.post(
    'http://127.0.0.1:8000/file',
    files=files,
    data={'first': "Hello", 'second': "World"}
)
print(response.json())
Sign up to request clarification or add additional context in comments.

2 Comments

i tried a similar thing with the base model, it works independently without a file and when i add a file, fastapi is not able to parse. class Data(BaseModel): first: str second: str async def temp_fn( data:Data,my_file: UploadFile = File(...))
I am not sure what is the issue in your case, ask a new question with a minimal reproducible example
3

I came across your question when I encountered this same issue. I was looking for a way I could make my endpoint accept a JSON body and a file (image). The answer is you can't.

This is because they both require different content-type and I don't think there is a way to set 2 content-type when making a request.

I noticed this when I opened the documentation. The content-type set to allow images is the reason the JSON is not accepted. That is the reason your program throws the error saying those fields are missing.

However, you can use a form to take in all the parameters you required in the JSON body as suggested by other comments. It should work fine as the values can still be accepted.

But for me, I opted to use an endpoint to accept the JSON without the image and give the object a default image. Then I created another endpoint to update the image.

Comments

0

I think you are missing a pretty fundamental point here.

@app.post('/file')
def my_function(param1: str,  param2: str):
    ...

Assume you have the code above, the request body it expects must be in this format.

{"param1": "some string", "param2": "some_string"}

The request body's keys should match your endpoint arguments. Otherwise, it would throw an error.

Let's say you are sending this request body

{'first': "Hello", 'second': "World"}

This will work.

@app.post("/dummy")
def my_function(first: str = Body(...), second: str = Body(...)):
    ...

This will fail

@app.post('/file')
def my_function(param1: str = Body(...),  param2: str = Body(...)):
    ...

In your example, the function for your /file endpoint expects two things in the request body, my_file and params but you are sending {'first': "Hello", 'second': "World"} instead of params. That's why it is raising an error.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.