alphanumeric
alphanumeric

Reputation: 19329

How to upload file using json and files arguments in request.post method

With Flask server:

from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    print('get_json: %s get_data: %s' % (type(request.get_json()), type(request.get_data())) )
    return 'OK', 200

app.run('0.0.0.0', 80)

the Client sends a request using both json and files arguments:

import requests 
files_data = {"dirname/file,name": bytearray(4)}
response = requests.post('http://127.0.0.1:80/', json = 'hello world', files = files_data)

the server prints that request.get_json() returns None.

get_json: <type 'NoneType'> get_data: <type 'str'>

How to pass hello world string to server?

Upvotes: 2

Views: 1117

Answers (2)

alphanumeric
alphanumeric

Reputation: 19329

The working solution is posted below:

server.py

import os 
import json 
import tempfile
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    print('get_json: %s get_data: %s' % (type(request.get_json()), type(request.get_data())) )

    for key, value in request.files.items():
        if value.content_type == 'application/json':
            data = json.loads(value.stream.read())
            print('got json data %s' % data)

        elif value.content_type == 'application/octet-stream':
            dst_filepath = os.path.join(tempfile.mktemp(), value.filename)
            if not os.path.exists(os.path.dirname(dst_filepath)):
                os.makedirs(os.path.dirname(dst_filepath))

            with open(dst_filepath, 'wb') as fd:
                for chunk in value: 
                    fd.write(chunk)
                print('saved file as %s' % dst_filepath)

    return 'OK', 200

app.run('0.0.0.0', 80)

client.py

import requests 
import json
import os 


payload = {"param_1": "value_1", "param_2": "value_2"}

filepath = '/file/path/to/local_file.zip'

files = {'json': ('some-json', json.dumps(payload), 'application/json'),
        'file': (os.path.basename(filepath), open(filepath, 'rb'), 'application/octet-stream')}

response = requests.post('http://127.0.0.1:80/', files=files)

Upvotes: 2

Dmitrii Sidenko
Dmitrii Sidenko

Reputation: 658

According to documentation:

Note, the json parameter is ignored if either data or files is passed.

Your json parameter must be json type, like this:

import requests 
json_data = {'data': 'hello world'}
files_data = {"dirname/file_name": bytearray(4)}
response = requests.post('http://127.0.0.1:80/', json = 'hello world')

If you want to use file and json together then don't encode using json.

Also do not set the Content-type header yourself, leave that to pyrequests to generate

payload = {"param_1": "value_1", "param_2": "value_2"}
    files = {
         'json': (None, json.dumps(payload), 'application/json'),
         'file': (os.path.basename(file), open(file, 'rb'), 'application/octet-stream')
    }

    r = requests.post(url, files=files)

For more information see this thread How to send JSON as part of multipart POST-request

Upvotes: 3

Related Questions