-2

I'm trying to make a POST request:

import requests


files = {'template': open('template.xlsx', 'rb')}
payload = {
    'context': {
        'OUT': 'csv',
        'SHORT': 'short'
    },
    'filename': 'file.xlsx',
    'content_type': 'application/excel'
}

r = requests.post('http://localhost:8000/render', files=files, data=payload)

to a FastAPI server:

from fastapi import FastAPI, UploadFile, Form
from pydantic import Json

app = FastAPI()


@app.post('/render')
def render(template: UploadFile, context: Json = Form(), filename: str = Form(...), content_type: str = Form(...)):
    # processing
    return "ok"

but I get this error (422 status code):

{"detail":[{"loc":["body","context"],"msg":"Invalid JSON","type":"value_error.json"}]}

As you can see, I'm trying to pass a file and request body at the same time. I guess I could fix this if converted payload['context'] into JSON. But I'd like to fix this on server side.

How can I fix the error? Maybe convert some before params passed into view or something like this?

Chris
  • 18,724
  • 6
  • 46
  • 80
  • 1
    Does this answer your question? [How to add both file and JSON body in a FastAPI POST request?](https://stackoverflow.com/questions/65504438/how-to-add-both-file-and-json-body-in-a-fastapi-post-request) – Chris Nov 14 '22 at 10:22

1 Answers1

0

You would need to serialise your JSON on client side, using json.dumps(), before sending the request. Additionally, you wouldn't really need to send metadata such as filename and content_type as part of your JSON payload. You can set the filename (which you can customise) and content_type explicitly in the multipart-encoded file, which you can later retrieve on server side using the UploadFile attributes. Further, the content_type (or mime type) of an .xlsx file shouldn't be application/excel, but, as described here and here, that should be application/vnd.openxmlformats-officedocument.spreadsheetml.sheet. Finally, I would also suggest you have a look at this answer, which explains the reason that you can't have both form-data/files and JSON together, and provides solutions that would allow one to submit both, and have the JSON data validated as well—in your case, the JSON data are not validated against a Pydantic model, meaning that the client can send any type of data or ommit any required attributes.

app.py

from fastapi import FastAPI, UploadFile, Form, File
from pydantic import Json

app = FastAPI()

@app.post('/render')
def render(file: UploadFile = File(...), context: Json = Form()):
    print(context, context['OUT'], file.filename, file.content_type, sep="\n")
    return "ok"

test.py

import requests
import json

url = 'http://localhost:8000/render'
files = {'file': ('file.xlsx', open('template.xlsx', 'rb'), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')}
payload = {'context': json.dumps({'OUT': 'csv','SHORT': 'short'})}
r = requests.post(url, files=files, data=payload)
print(r.json())
Chris
  • 18,724
  • 6
  • 46
  • 80