I have this issue where I am trying to send/receive to a flask API some file and JSON in a single function.
On my client ( sender ) I have :
#my json to be sent
datas = {'var1' : 'var1','var2' : 'var2',}
#my file to be sent
local_file_to_send = 'user_picture.jpg'
url = "http://10.100.2.6:80/customerupdate"
headers = {'Content-type': 'multipart/form-data'}
files = {'document': open(local_file_to_send, 'rb')}
r = requests.post(url, files=files, data=datas, headers=headers)
On my Flask server I have :
class OPERATIONS(Resource):
@app.route('/',methods=['GET'])
def hello_world():
return 'Hello World!'
@app.route('/customerupdate',methods=['GET','POST'])
def customerupdate():
event_data_2 = json.loads(request.get_data().decode('utf-8'))
print event_data_2
I have this error message telling me that the data is actually not a json format nor a utf8 format. If I print the content of the "get_data" without trying to decode it shows some binary characters..
What would be the syntax on my client to read the json and write the file locally ?
I would recommend sending both the JSON and the file as parts of the multipart form. In that case you would read them from request.files
on the server. (One caveat: I tested all my examples with Python 3, requests 2.18.4, and Flask 0.12.2 -- you might need to change the code around to match your environment).
From https://stackoverflow.com/a/35940980/2415176 (and the Flask docs at http://docs.python-requests.org/en/latest/user/advanced/#post-multiple-multipart-encoded-files), you don't need to specify headers or anything. You can just let requests
handle it for you:
import json
import requests
# Ton to be sent
datas = {'var1' : 'var1','var2' : 'var2',}
#my file to be sent
local_file_to_send = 'tmpfile.txt'
with open(local_file_to_send, 'w') as f:
f.write('I am a file\n')
url = "http://127.0.0.1:3000/customerupdate"
files = [
('document', (local_file_to_send, open(local_file_to_send, 'rb'), 'application/octet')),
('datas', ('datas', json.dumps(datas), 'application/json')),
]
r = requests.post(url, files=files)
print(str(r.content, 'utf-8'))
Then on the server you can read from request.files
(see http://flask.pocoo.org/docs/0.12/api/#flask.Request.files but note that request.files used to work a little differently, see https://stackoverflow.com/a/11817318/2415176):
import json
from flask import Flask, request
app = Flask(__name__)
@app.route('/',methods=['GET'])
def hello_world():
return 'Hello World!'
@app.route('/customerupdate',methods=['GET','POST'])
def customerupdate():
posted_file = str(request.files['document'].read(), 'utf-8')
posted_data = json.load(request.files['datas'])
print(posted_file)
print(posted_data)
return '{}\n{}\n'.format(posted_file, posted_data)
Thanks to Craig answer, I found the solution. I will post both code ( client and server ) to help in case of future use. The CLient server is uploading file and Json in the "form" feature of flask. Then some ast and some dict to make the Payload clearer ( I know this is ugly way, but this is the best scholar approach )
On Client side :
datas = {'CurrentMail': "AA", 'STRUserUUID1': "BB", 'FirstName': "ZZ", 'LastName': "ZZ", 'EE': "RR", 'JobRole': "TT" }
#sending user infos to app server using python "requests"
url = "http://10.100.2.6:80/customerupdate"
def send_request():
payload = datas
local_file_to_send = 'user_picture.jpg'
files = {
'json': (None, json.dumps(payload), 'application/json'),
'file': (os.path.basename(local_file_to_send), open(local_file_to_send, 'rb'), 'application/octet-stream')
}
r = requests.post(url, files=files)
send_request()
On Flask Server side :
import sys, os, logging, time, datetime, json, uuid, requests, ast
from flask import Flask, request , render_template
from werkzeug import secure_filename
from werkzeug.datastructures import ImmutableMultiDict
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
app.debug = True
class OPERATIONS(Resource):
@app.route('/',methods=['GET'])
def hello_world():
return 'Hello World!'
@app.route('/customerupdate',methods=['GET','POST'])
def customerupdate():
print "************DEBUG 1 ***********"
RequestValues = request.values
print RequestValues
print "************DEBUG 2 ***********"
RequestForm = request.form
print RequestForm
print "************DEBUG 2-1 ***********"
so = RequestForm
json_of_metadatas = so.to_dict(flat=False)
print json_of_metadatas
print "************DEBUG 2-2 ***********"
MetdatasFromJSON = json_of_metadatas['json']
print MetdatasFromJSON
print "************DEBUG 2-3 ***********"
MetdatasFromJSON0 = MetdatasFromJSON[0]
print MetdatasFromJSON0
print "************DEBUG 3-5 ***********"
strMetdatasFromJSON0 = str(MetdatasFromJSON0)
MetdatasDICT = ast.literal_eval(strMetdatasFromJSON0)
print MetdatasDICT
print "************DEBUG 3-5 ***********"
for key in MetdatasDICT :
print "key: %s , value: %s" % (key, MetdatasDICT[key])
print "************DEBUG 4 ***********"
f = request.files['file']
f.save(secure_filename(f.filename))
print "FILE SAVED LOCALY"
return 'JSON of customer posted'
If this is not in production, there is an easier way than binding the json in files, send in the json data as param value instead of binding it in json.
datas = {data: {'var1' : 'var1','var2' : 'var2}}
url = "http://10.100.2.6:80/customerupdate"
files = {'document': open(local_file_to_send, 'rb')}
headers = {'Content-type': 'application/json'}
r = requests.post(url, files=files, params=datas, headers=headers)
and in flask server accept data and file as:
image = request.files.get('image')
data = request.args.get('data')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With