'How to post an image file with a list of strings using FastAPI?

I have tried a lot of things, but it doesn't seem to work. Here is my code:

@app.post("/my-endpoint")
async def my_func(
    languages: List[str] = ["en", "hi"], image: UploadFile = File(...)
):

The function works fine when I remove one of the parameters, but with both of the parameters, the retrieved list comes out to be like ["en,hi"], whereas I want it to be ["en, "hi].

I am not even sure if my approach is correct, hence the broader question, if this approach is not right then how can I post a list and an image together?



Solution 1:[1]

Your function looks okay. The problem for that behaviour has to do with how OpenAPI (Swagger UI) - I am assuming you are using it for testing, as I did myself and noticed the exact same behaviour - handles the list items. For some reason, OpenAPI adds all items as a single item to the list, separated by comma (i.e., ["en, hi, ..."], instead of ["en", "hi", ...]).

Testing the code with Python requests and sending the languages' list in the proper way, it works just fine. To fix, however, the behaviour by OpenAPI, or any other tool that might behave the same, you could check the length of the list that is received in the function, and if it is equal to 1 (meaning that the list contains a single item), then split this item using comma delimiter to get a new list of all languages included.

Below is a working example:

app.py

import uvicorn
from fastapi import File, UploadFile, FastAPI
from typing import List

app = FastAPI()

@app.post("/submit")
async def submit(languages: List[str] = ["en", "hi"], image: UploadFile = File(...)):
        if (len(languages) == 1):
            languages= [item.strip() for item in languages[0].split(',')]
        return {"Languages ": languages, "Uploaded filename": image.filename}

if __name__ == '__main__':
    uvicorn.run(app, host='127.0.0.1', port=8000, debug=True)

test.py

import requests

url = 'http://127.0.0.1:8000/submit'
image = {'image': open('sample.png', 'rb')}
#payload ={"languages": ["en", "hi"]}  # send languages as separate items
payload ={"languages": "en, hi"}  # send languages as a single item
resp = requests.post(url=url, data=payload, files=image) 
print(resp.json())

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1