I am trying to create REstful Web Service using Flask. But i am having trouble in processing the xml data in the GET request.
uri="http://127.0.0.1:5000/test/api/getfamilyinfo"
request_body='''
<StayInfo>
<district>Khurda</district>
<village>BBSR</village>
<unit>Hogwarts</unit>
</StayInfo>
'''
body_format = {'Content-Type': 'application/xml'}
requests.get(uri, data = request_body, verify = False, headers = body_format)
I am getting error:
File "C:\Python27\lib\xml\etree\ElementTree.py", line 647, in parse
source = open(source, "rb")
TypeError: coercing to Unicode: need string or buffer, Response found</textarea>
My Code:
#app.route('/test/api/getfamilyinfo', methods=['GET'])
def getfamilyinfo():
errors = []
results = {}
if request.method == "GET":
try:
r=request.data
except Exception,e:
resp = jsonify({"error": str(e)})
return resp, status.HTTP_400_BAD_REQUEST
if r:
eTree = ElementTree.parse(r) ## The code is breaking here
Kindly help me to understand where i am going wrong. Thanks in advance.
ElementTree.parse() (docs) expects a filename (or file object).
You want ElementTree.fromstring() (docs).
Related
I have an endpoint which is receiving a text file from a request, which the flask server processes and now need to send a response which should be a json file. I have read and performed the operations of received txt file, and now when I send the dict by jsonify I get this in terminal.
Response 444 bytes [200 OK]
How do I get the json file or is there any other way of sending the JSON file in response? Since I won't be in control of the server that will send the request I need a way to send JSON file.
Code Handling the response
#app.route('/automated_testing', methods=['GET','POST'])
def getfile():
if request.method == 'POST':
for file in request.files:
links = request.files[file].read()
#Since a byte sized object is returned
links = [links.decode('utf8').strip()]
links = links[0].split("\n")
res = dict()
for i in links:
f = FlarePredictor(i)
res[i] = f[0]
print(jsonify(res), file=sys.stderr)
return jsonify(res)
else:
return "GET REQ"
return "Hi"
Code used to send the request
import requests
with open('test.txt', 'rb') as f:
r = requests.post('http://127.0.0.1:5000/automated_testing', files={'test.txt': f})
requests supports JSON out-of-the-box:
json = r.json()
Now json will be a regular Python dictionary containing the data.
While implementing a rest API in python flask, I have used several options to return a file (any type) , read it and save it to local repository of request but encountered with multiple errors as below:
Case 1:
def download_file():
return send_file('any_file.pdf')
r = requests.get(url = 'http://localhost:5000/download').read()
has responded with a error Response object has no attribute read/text/content
Case 2:
def download_file():
file = open('any_file.pdf','r').read()
return file
r = requests.get(url = 'http://localhost:5000/download')
has responded with a error Return doesn't accept this
So How can I do this as flask is not allowing to return a file without response object and response object is not readable and doesn't support to save that file directly.
The Flask server code in Case 1 is correct. A more complete example:
#app.route('/download')
def download_file():
# Some logic here
send_file('any_file.pdf')
However the Response object returned by requests.get doesn't have a read method. The correct way is to use:
Response.content: Content of the response, in bytes.
So, the client code should be:
r = requests.get('http://localhost:5000/download')
bytes = r.content
# Now do something with bytes, for example save it:
with open('downloaded_file.ext', 'wb') as f:
f.write(bytes)
In the Django Rest Framework I would like to post a file, received as an InMemoryUploadedFile, to a different server as soon as it is received.
It sounds simple, but the request.post() function does not seem to properly send over such a file :
def post(self, request, *args, **kwargs):
data = request.data
print(data)
# <QueryDict: {'file': [<InMemoryUploadedFile: myfile.pdf (application/pdf)>]}>
endpoint = OTHER_API_URL + "/endpoint"
r = requests.post(endpoint, files=data)
My other server receives the request (through flask) with the name of the file, but not the content:
#app.route("/endpoint", methods=["POST"])
def endpoint():
if flask.request.method == "POST":
# I removed the many checks to simplify the code
file = flask.request.files['file']
path = os.path.join(UPLOAD_FOLDER, file.filename)
file.save(path)
print(file) #<FileStorage: u'file.pdf' (None)>
print(os.path.getsize(path)) #0
return [{"response":"ok"}]
When posting a file directly to that api in form-data with postman, It works as expected:
print(file) # <FileStorage: u'file.pdf' ('application/pdf')>
print(os.path.getsize(path)) #8541
Any help on how to fix this, i.e. transform the InMemoryUploadedFile type in something a normal REST api can understand? Or maybe just adding the right headers?
I had to figure this issue out passing an uploaded file from a Django front end website to a Django backend API in Python 3. The InMemoryUploadedFile's actual file data can be accessed via the object's .file property's .getvalue() method.
path="path/to/api"
in_memory_uploaded_file = request.FILES['my_file']
io_file = in_memory_uploaded_file.file
file_value = io_file.getvalue()
files = {'my_file': file_value}
make_http_request(path, files=files)
and can be shortened
file = request.FILES['my_file'].file.getvalue()
files = {'my_file': file}
Before this, trying to send InMemoryUploadFile objects, the file property, or the result of the read() method all proved to send a blank/empty file by the time it got to the API.
I had the same problem and the same case.
My working solution
headers = {
"Host": API_HOST,
"cache-control": "no-cache",
}
try:
data = json_request = request.POST['json_request'].strip()
data = json.loads(data) # important!
except:
raise Http404
try:
in_memory_uploaded_file = request.FILES['file'].file.getvalue()
files = {'photo': in_memory_uploaded_file} # important!
except:
files = {}
if USE_HTTPS:
API_HOST = f'https://{API_HOST}'
else:
API_HOST = f'http://{API_HOST}'
if authorization_key and len(authorization_key) > 0:
response = requests.post(f'{API_HOST}/api/json/?authorization_key={authorization_key}', headers=headers, data=data, files=files)
else:
response = requests.post(f'{API_HOST}/api/json/', headers=headers, data=data)
json_response = json.dumps(response.json())
I need help with python requests. I want to post a file to a server. Here is my example code for posting the file
import requests
with open('try.txt', 'rb') as myfile:
url = <myurl>
files = {'value':myfile}
response = requests.post(url, files=files)
try.txt is not a blank file. It contains some sentences
On the server side, here is the snippet for receiving the file.
from flask_restful import Api, Resource, reqparse
class MyThing(Resource):
def get(self):
pass
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('value')
args = parser.parse_args()
value = args['value']
if value.endswith(".txt") or value.endswith(".csv"):
## do something
else:
## do something
However when I run the server and try to post the file to the server, it return an error saying that
if value.endswith(".txt") or value.endswith(".csv"):
AttributeError: 'NoneType' object has no attribute 'endswith'
I check the value by print files and it return like this
{'value': <open file 'try.txt', mode 'rb' at 0x7f041db8e420>}
Does this mean value is null? or did I missed something on my server side code? Thank you for the help.
I have been following this tutorial to download some page info from fb.
I am using Python 3.5 and the tutorial is using python2.
I was having some issues at first with a HTTP error code 400, basically saying I had to use the https protocol instead of http. So I have test in idle now that the data in coming and it looks to a novice like me as JSON. But when I try passing it to the json.loads it is giving this error
Traceback (most recent call last):
File "C:\Users\Levo\Desktop\facebookscrape.py", line 38, in <module>
testFacebookPageData(page_id, access_token)
File "C:\Users\Levo\Desktop\facebookscrape.py", line 34, in testFacebookPageData
data = json.loads(requests_until_succeed(url))
File "C:\Users\Levo\AppData\Local\Programs\Python\Python35\lib\json\__init__.py", line 312, in loads
s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'
Apart from using the urllib library instead of the urllib2 library and https instead of http I don't what I am doing wrong? is the encryption of https the problem??
def requests_until_succeed(url):
req = urllib.request.Request(url)
success = False
while success is False:
try:
response = urllib.request.urlopen(req)
if response.getcode() == 200:
success = True
except Exception as e:
print(e)
time.sleep(5)
print ("Error for URL %s: %s" % (url, datetime.datetime.now()))
return response.read()
def testFacebookPageData(page_id, access_token):
base = "https://graph.facebook.com/v2.6"
node = "/" + page_id + "/feed"
parameters = "/?access_token=%s" % access_token
url = base + node + parameters
data = json.loads(requests_until_succeed(url))
print(json.dumps(data, indent = 4, sort_keys=True))
testFacebookPageData(page_id, access_token)
json.loads accepts python3 string, which is unicode, and responce.read() returns binary string.
Use data = json.loads(requests_until_succeed(url).decode('utf-8')) because responce is most likely utf-8.