How to pass string and multiple files using FastAPI and Python requests?

Question:

I am using the following FastAPI endpoint that accepts multiple files:

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

app = FastAPI()

@app.post("/multiplefiles")
async def _file_upload(keywords, files: List[UploadFile] = File(...)): #create_file
    return {"len_files": keywords}

I would like to first input the keywords parameter, then the list of files, but I cannot find a way to perform a valid post request:

import requests

files = (("keywords", "key1"),
    [
    ('files', open('filesfile1.pdf', 'rb')), 
    ('files', open('filesfile2.pdf', 'rb'))
    ]
)

response = requests.post('http://127.0.0.1:3000/multiplefiles', files=files)
print(response.json())

If I only upload the files as a list of tuple work, but I do not know how to pass in the keywords parameter.

Asked By: ardito.bryan

||

Answers:

Option 1 – Define query parameter as str

In the way the keywords parameter is defined in your endpoint is expected to be a query parameter. If you expect it to be a single string value, you can define it using str as follows:

Server side:

@app.post("/")
def upload(keywords: str, files: List[UploadFile] = File(...)):
    return {"keywords": keywords}

Since it is expected as query parameter, you should use the params argument in Python requests, in order to pass query parameters, as described here. Example:

Client side:

url = 'http://127.0.0.1:8000/'
data = {'keywords': 'key1'}
r = requests.post(url, files=files, params=data)
print(r.json())

You could also pass it directly to the URL instead:

url = 'http://127.0.0.1:8000?keywords=key1'

Option 2 – Define query parameter as List

If you are sending a list of keywords, you have to declare the keywords query parameter with a type of List (or list in Python 3.9+), and define it explicitly with Query, so that it can receive a list of values, or in other words, to receive multiple values—see related answers here, here and here (for arbitrary query parameters see this and this). Example:

Server side:

from fastapi import Query

@app.post("/")
def upload(keywords: List[str] = Query(...), files: List[UploadFile] = File(...)):
    return {"keywords": keywords} 

Client side:

url = 'http://127.0.0.1:8000/'
data = {'keywords': ['key1', 'key2']}
r = requests.post(url, files=files, params=data)
print(r.json())

If you would like to add the list of keywords to the URL’s query string yourself, it should then look like this:

url = 'http://127.0.0.1:8000?keywords=key1&keywords=key2'

Option 3 – Use Form parameters

If you would like to use Form parameters instead to pass additional data along with files, please have a look at this answer.

Answered By: Chris
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.