Search code examples
pythonrestflaskpython-requests

Send request with a pdf file and a json to an API generated with flask


I have this Flask app:

from flask import Flask, request

app = Flask(__name__)

@app.post('/upload')
def upload_file_json():
    
    file = request.files['file']
    
    num_1 = int(request.form['AA_num'])
    num_2 = int(request.form['BB_num'])
    

    return {"type":type(file), "num": num_1 + num_2}

I use this request but is not working:

import requests


api_url = 'http://127.0.0.1:5000/upload'  
pdf_path = 'my_CV.pdf'

headers = {
    'Content-Type': 'multipart/form-data',
}

# Prepare the payload
payload = {
    'file': open(pdf_path, 'rb'),
    'AA_num': "34",
    'BB_num': "55"
    }


response = requests.post(api_url, headers=headers, files=payload)


print(response.json())

What is the right request that I need to use to be able to call the API?

I tried other requests taking similar responses from Stack Overflow but none worked.


Solution

  • In addition to the answer @pjones123 provided, you are also passing insufficient data to the Content-Type: "multipart/form-data" header. Therefore your flask application will fail to separate the file from the form data. You can see that if you print request.data. It will contain all of the posted data however your request.files will be empty.

    When you change your code to omit the headers, you will notice that requests library will correctly handle your file input and set the header to the correct value:

    Content-Type: "multipart/form-data; boundary=70ff03c8b3468b58e0e29907668e...."
    

    In a normal html form (<form enctype="multipart/form-data">...</form>) the browser handles the boundary of your file. Boundary means the separation of the file data from the other field data. The backend needs to know where your file ends and where other form data starts.

    So the correct version is:

    payload = {
        "AA_num": "34",
        "BB_num": "55",
    }
    files = {
        "file": ("test.pdf", open(pdf_path, "rb")),
    }
    requests.post(api_url, files=files, data=payload)