I am writing a flask backend with flask sqlalchemy and marshmallow which returns json and kivy as frontend. I am trying to login in my flask api using kivy urlrequest but no data is been passed. I get error from my flask api ('no input data provided') even so i passed valid data.
from kivy.network.urlrequest import UrlRequest
import urllib
import json
def success(req, result):
print('success')
def fail(req, result):
print('fail')
def error(req, result):
print('error')
def progress(req, result, chunk):
print('loading')
values = {'email':'wilson#gmail.com', 'pwdhash':'wilson'}
params = urllib.urlencode(values)
headers = {'Content-type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
req = UrlRequest('http://127.0.0.1:5000/login', on_success=success, on_failure=fail, on_error=error, on_progress=progress, req_body=params, req_headers=headers)
req.wait()
print(req.result)
please how to fix this?
And to answer my question
My API only accepts json data and i never passed one just plain text. To fix this, i called json.dumps to convert the data into json and changed the Content-type from application/x-www-form-urlencoded to application/json
below is the fixed code:
from kivy.network.urlrequest import UrlRequest
import urllib
import json
def success(req, result):
print('success')
def fail(req, result):
print('fail')
def error(req, result):
print('error')
def progress(req, result, chunk):
print('loading')
values = {'email':'wilson#gmail.com', 'pwdhash':'wilson'}
# converted data to json type
params = json.dumps(values)
# changed Content-type from application/x-www-form-urlencoded to application/json
headers = {'Content-type': 'application/json',
'Accept': 'text/plain'}
req = UrlRequest('http://127.0.0.1:5000/login', on_success=success, on_failure=fail, on_error=error, on_progress=progress, req_body=params, req_headers=headers)
req.wait()
print(req.result)
Related
I wrote endpoint called foobar in default.py controller of web2py, it looks like
#service.json
def foobar(*args, **vars):
payload = request.vars.student
print(payload)
#Above payload prints [rollNo, firstName, lastName]
#Expected is {"rollNo": 6299857, "FirstName": Prasad, "LastName": Telkikar}
fileObj= request.vars.video
studentActivity = fileObj.file.read()
#Currently I am unable to do it from unit test, but it works from postman
print(f"Student's Roll number = {payload.rollNo} \n FirstName = {payload.firstName}, \n lastName = {payload.lastName}, fileSize = {fileObj.file.tell()}")
#storing studentActivity video to specific location
#Doing business logic
Now I am writing unit test for this endpoint, where i am trying to call this endpoint using requests,
import requests
import unittest
...
class TestStudentsData(unittest.TestCase):
def test_Individual_student(self):
payload = dict(rollNo=6299857, firstName="Prasad", lastName="Telkikar")
url = "http://127.0.0.1:8000/v1/foobar"
header = dict(Authorization="Bearer <Token>")
response = requests.post(url,files={'studentActivity':open("Activity.mp4", 'rb')}, data=payload, headers=headers)
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main(verbosity=2)
Here I am unable to pass student payload as a json.
How can I pass json payload with studentActivity file using requests?
What I tried so far?
I tried both the approaches given in this SO answer.
I read requests documentation where it says "the json parameter is ignored if either data or files is passed" requests documentation
I resolved this problem by adding proper content-type to payload,
import os
...
filePath = os.getcwd()
files = {'studentActivity':open(filePath, "Activity.mp4", 'rb'),
'payload':(None, payload, 'application/json')}
#^^^^^^^^^^^^^^^^^ This was missing
response = requests.post(url,files={'studentActivity':open("Activity.mp4", 'rb')}, data=payload, headers=headers)
I am trying to read the response after I have made a call to an API using python Twisted web client. I have made a POST call to the endpoint passing in a json structure, it should then return a status with either a message (if failed) or a json strucure if successful.
Using the code below I am able to see the message is getting called along with the status code, but I am not seeing the message/json structure.
The 'BeginningPrinter' is never getting called and I don't uderstand why.
Example of output:
$ python sample.py
Response version: (b'HTTP', 1, 0)
Response code: 401 | phrase : b'UNAUTHORIZED'
Response headers:
Response length: 28
Apologies that the code is so long, but I wanted to make sure it contains everything that I used to run it in it.
from io import BytesIO
import json
from twisted.internet import reactor
from twisted.web.client import Agent
from twisted.web.http_headers import Headers
from twisted.internet.defer import Deferred
from twisted.internet.protocol import Protocol
from twisted.web.client import FileBodyProducer
agent = Agent(reactor)
class BeginningPrinter(Protocol):
def __init__(self, finished):
self.finished = finished
self.remaining = 1024 * 10
print('begin')
def dataReceived(self, bytes):
print('bytes')
if self.remaining:
display = bytes[:self.remaining]
print('Some data received:')
print(display)
self.remaining -= len(display)
def connectionLost(self, reason):
print('Finished receiving body:', reason.getErrorMessage())
self.finished.callback(None)
TESTDATA = { "keySequence": "2019-07-14" }
jsonData = json.dumps(TESTDATA)
body = BytesIO(jsonData.encode('utf-8'))
body = FileBodyProducer(body)
headerDict = \
{
'User-Agent': ['test'],
'Content-Type': ['application/json'],
'APIGUID' : ['ForTesting']
}
header = Headers(headerDict)
d = agent.request(b'POST', b' http://127.0.0.1:5000/receiveKeyCode', header, body)
def cbRequest(response):
print(f'Response version: {response.version}')
print(f'Response code: {response.code} | phrase : {response.phrase}')
print('Response headers:')
print('Response length:', response.length)
print(pformat(list(response.headers.getAllRawHeaders())))
print(response.deliverBody)
finished = Deferred()
response.deliverBody(BeginningPrinter(finished))
return finished
d.addCallback(cbRequest)
def cbShutdown(ignored):
#reactor.stop()
pass
d.addBoth(cbShutdown)
reactor.run()
You don't need all of that fluff code, if you are already using Flask then you can write to the API and get the values back in a few lines, If you are not then it makes sense to pip install it as it makes life a lot easier.
import json
import requests
headers = {
'content-type': 'application/json',
'APIGUID' : 'ForTesting'
}
conv = {"keySequence": "2019-07-14"}
s = json.dumps(conv)
res = requests.post("http://127.0.0.1:5000/receiveKeyCode",data=s, headers=headers)
print(res.text)
Reference: See this Stackoverflow link
I am currently able to send OpenCV image frames to my Flask Server using the following code
def sendtoserver(frame):
imencoded = cv2.imencode(".jpg", frame)[1]
headers = {"Content-type": "text/plain"}
try:
conn.request("POST", "/", imencoded.tostring(), headers)
response = conn.getresponse()
except conn.timeout as e:
print("timeout")
return response
But I want to send a unique_id along with the frame I tried combining the frame and the id using JSON but getting following error TypeError: Object of type 'bytes' is not JSON serializable does anybody have any idea how I can send some additional data along with the frame to the server.
UPDATED:
json format code
def sendtoserver(frame):
imencoded = cv2.imencode(".jpg", frame)[1]
data = {"uid" : "23", "frame" : imencoded.tostring()}
headers = {"Content-type": "application/json"}
try:
conn.request("POST", "/", json.dumps(data), headers)
response = conn.getresponse()
except conn.timeout as e:
print("timeout")
return response
I have actually solved the query by using the Python requests module instead of the http.client module and have done the following changes to my above code.
import requests
def sendtoserver(frame):
imencoded = cv2.imencode(".jpg", frame)[1]
file = {'file': ('image.jpg', imencoded.tostring(), 'image/jpeg', {'Expires': '0'})}
data = {"id" : "2345AB"}
response = requests.post("http://127.0.0.1/my-script/", files=file, data=data, timeout=5)
return response
As I was trying to send a multipart/form-data and requests module has the ability to send both files and data in a single request.
You can try encoding your image in base64 string
import base64
with open("image.jpg", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
And send it as a normal string.
As others suggested base64 encoding might be a good solution, however if you can't or don't want to, you could add a custom header to the request, such as
headers = {"X-my-custom-header": "uniquevalue"}
Then on the flask side:
unique_value = request.headers.get('X-my-custom-header')
or
unique_value = request.headers['X-my-custom-header']
That way you avoid the overhead of processing your image data again (if that matters) and you can generate a unique id for each frame with something like the python uuid module.
Hope that helps
IN the code below, I am trying to make a POST of data with urllib2. However, I am getting a HTTP 400 bad request error. Can anyone help me with why this might be the case? The URL is reachable from my computer and all relevant ports are open.
data = {'operation' : 'all'}
results = an.post(an.get_cookie(), 'http://{}:8080/api/v1/data/controller/core/action/switch/update-host-stats'.format(an.TARGET), data)
print results
def post(session_cookie, url, payload):
data = urllib.urlencode(payload)
req = urllib2.Request(url, data)
req.add_header('Cookie','session_cookie=' + session_cookie)
try:
returnedData = urllib2.urlopen(req, data, timeout = 30)
data = json.load(returnedData)
except urllib2.URLError, e:
print e.code
print 'URL ERROR'
return {}
return data
The following code works for me:
import json
import urllib2
import logging
def post_json_request(url, post_data, optional_headers = {}):
"""
HTTP POST to server with json as parameter
#param url: url to post the data to
#param post_data: JSON formatted data
#return: response as raw data
"""
response = ""
try:
req = urllib2.Request(url, post_data, optional_headers)
jsonDump = json.dumps(post_data)
response = urllib2.urlopen(req, jsonDump)
except Exception, e:
logging.fatal("Exception while trying to post data to server - %s", e)
return response
I'm using it in various stubborn platforms that insist to retrieve data on a specific method.
Hope it will help,
Liron
I was trying to retrieve data from an API and i was receiving
'set' object has no attribute 'items'
This is my api.py and i have import it to my views
import json
import urllib
import urllib2
import pycurl
def get_resources(request, filter, endpoint, lookup):
headers = {'X-Auth-Token:%s' % request.user.token, 'Content-Type:application/json'}
data = urllib.urlencode(filter)
url = endpoint+lookup
req = urllib2.Request(url, data, headers)
response = urllib2.urlopen(req)
result = json.loads(response.read())
return result
and my views.py is like this
def indexView(request):
resources = json.dumps(get_resources(request,{}, api_endpoint, '/v2/meters'))
return HttpResponse(resources, mimetype='application/json')
I know that i was doing wrong here, I hope someone who could help me thanks.
The line:
headers = {'X-Auth-Token:%s' % request.user.token,
'Content-Type:application/json'}
defines a set. And it should probably be a dictionary (which has : somewhere in after which follows the value for the key before the :)
Try something like that:
headers = {'X-Auth-Token': request.user.token, 'Content-Type': 'application/json'}