I am working on a rest api using flask. Currently the code for the client is as follows:
new_data = {'msg': message,
'rec':rec_id,
'snd':my_id}
requests.post("http://localhost:33/api/resources/messages/all", json = new_data)
I did print out new_data and it does print fine it does print out fine
{'msg': 'This is a message', 'rec': 1, 'snd': 0}
and the code in the rest api is:
#app.route('/api/resources/messages/all', methods=['GET', 'POST'])
def api_messages():
if request.method == "GET":
return jsonify(messages)
if request.method == "POST":
sentmsg = request.json
print (sentmsg)
changing
sentmsg = request.json
to
sentmsg = request.get_json()
did not change anything as it still results in the same error. Specifying the content type also did not result in any changes to the result.
However this code results in the error when attempting to post it.
TypeError: Object of type type is not JSON serializable
How can I change this code in order to make it so the json is passed to the rest api and can be printed out in json form.
The issue did not originate from the code shown in the initial post. The error originates at the start of the code where I declared two of the variables used here:
my_id = int
rec_id = int
Since these 2 variables did not have a value it was causing issues when it was called. As such it resulted in the error message "TypeError: Object of type type is not JSON serializable" (This error message itself gives a good indicator that one or more of the variables used were likely blank and held no value, thus making it unable to specify the data type in the message).
As such giving these variables an actual value caused the program to work fine. A second error that only become obvious after was that request.get_json needed to have brackets after get_json, making it request.get_json().
Related
I get the next xml response in a webservice:
<error>failed to communicate with device</error>
And I want to save the error message, so I do the next (I do it in others situations and work but not in this case):
[...]
if tree.tag == 'error':
mensaje = tree.find('error')
print('The error is: '+mensaje)
And I get None. If I put mensaje = tree.find('error').text I get a error because NoneType has no attribute text.
Why can't I get the error message?
Thanks
I 'think' I have some caching issue.
my webservice is receiving data through POST request and saving it to disk.
Following is my code:
#app.route('/ws_part' , methods=['POST'])
def ws_part():
request_data = request.get_json()
#placeholder for workstation number and part number
received_data ={'ws_no':request_data['workstation'],
'part_no':request_data['part']}
#Checking if workstation number is already available
global updated
updated = 'no'
for i in repository:
if i['ws'] == received_data['ws']:
i['part'] = received_data['part']
updated = 'yes'
if(updated!='yes'):
new_input = received_data
repository.append(new_input)
return jsonify({'repository': repository})
Issue I am facing:
1.The very first request goes through successfully and gives 200 OK response and workstation number and part coming with the request get saved in 'repository' placeholder.
2.But the very next request throws 500 server error
Error:
File "API_ws_par.py", line 23, in ws_part
if i['ws'] == received_data['ws']:
KeyError: 'ws'
3.Funny thing happening is:
If at this point I restart my web service and trigger the POST request again, the data coming with this new request is getting overwritten and I am losing my previously saved data.
4.Also, the consequent second POST request throws the same 500 server error
Please, guide if this is something to do with cache?
If yes, then please let me know how to do it?
Thanks in advance.
this is not a caching problem, it's a problem in the logic of the function,
on the first call, you probably don't get to the line of code generating the exception,
The problem is on the second call, the key name is not 'ws' it's 'ws_no',
if you change these lines:
for i in repository:
if i['ws'] == received_data['ws_no']:
i['part'] = received_data['part_no']
updated = 'yes'
to use 'ws_no', and 'part_no' you won't have the key error.
I have a Google App Engine API using Python and NDB working except for HTTP response code/error checking. I put in some code to handle 406 (to only accept json requests) and 400 errors (to prevent a user from leaving a required field blank) to the post function for one of my entities but now it seems to have broken my code. This is the code with the error checking included:
class Task_action(webapp2.RequestHandler):
def post(self):
#Only allows a JSON, if not, then error
if 'application/json' not in self.request.accept:
self.response.status = 406
self.response.status_message = "Not Acceptable, API only supports application/json MIME type"
return
new_task = Task(parent=PARENT_KEY,
name = self.request.get("task_name"),
hours = int(self.request.get("task_hours")),
id = self.request.get("task_name"))
#has error code, since name and hours is required
if name:
new_task.name = name
else:
self.response.status = 400
self.response.status_message = "Invalid request, task name is Required."
if hours:
new_task.hours = hours
else:
self.response.status = 400
self.response.status_message = "Invalid request, task hours is Required."
key = new_task.put()
out = new_task.to_dict()
self.response.write(json.dumps(out))
I am using curl to test it:
curl --data-urlencode "name=clean" -H "Accept: application/json" http://localhost:15080/task
I know the problem is in the error checking code (all the if else statements) because when I take it out the curl test works fine and the object is added to the ndb database correctly. However, with the error checking code included my curl test does not add the object as it should. Does anyone have an idea why the error checking code is breaking my post statement? Is there a better way to return HTTP error response codes?
You had some uninitialized variables in the code (name, hours, maybe PARENT_KEY) and also you didn't return after preparing the error response, thus flowing in areas where the code wouldn't work.
I'd suggest re-organizing the error checking code for minimal impact on the functional code (checks should be done as early as possible, to simplify the remaining functional code. Also, I prefer to use the more concise webapp2.abort() function (which doesn't need a return statement).
Something along these lines:
class Task_action(webapp2.RequestHandler):
def post(self):
# Only allows a JSON, if not, then error
if 'application/json' not in self.request.accept:
webapp2.abort(406, details="Not Acceptable, API only supports application/json MIME type")
# request must contain a valid task name
name = self.request.get("task_name")
if not name:
webapp2.abort(400, details="Invalid request, task name is Required.")
# request must contain a valid task hours
try:
hours = int(self.request.get("task_hours"))
except Exception:
hours = 0
if not hours:
webapp2.abort(400, details="Invalid request, task hours is Required.")
new_task = Task(parent=PARENT_KEY, name=name, hours=hours, id=hours)
new_task.name = name # isn't this done by Task() above?
new_task.hours = hours # isn't this done by Task() above?
key = new_task.put()
out = new_task.to_dict()
self.response.write(json.dumps(out))
Another note: you're specifying the id parameter in the Task() call, which doesn't work unless you know each Task() entity has a unique hours value. You may want to let the datastore assign IDs automatically.
I'm writing an app to post json to Django, but get a 500 error in terminal like
[27/Jan/2015 20:50:38] "POST /datasave/ds/ HTTP/1.1" 500 10414
This is my jQuery code:
$(function() {
$('#upload').click(function() {
var json_obj = {
username: $('#username').val(),
password: $('#password').val(),
game_id1: '123',
csrfmiddlewaretoken: '{{ csrf_token}}'
};
$.post("http://192.168.0.109:8000/datasave/ds/", JSON.stringify(json_obj),
function(data) {
alert("OK");
},
"json");
})
})
And Django views code:
#csrf_exempt
def ds(request):
dicty = {}
if request.is_ajax:
if request.method == 'POST':
req = json.loads(request.body.decode("utf-8"))
obj, created =
Gamer.objects.update_or_create(
username=req.get(u'username', None),
password=req.get(u'password', None),
game_id1=req.get(u'game_id1', None))
print obj, created
dicty['username'] = req.get(u'username', None)
dicty['password'] = req.get(u'password', None)
dicty['create_at'] = str(timezone.now())
return JsonResponse(dicty)
As you are getting a 500 Internal server error one could assume that there is an issue in your view handler code. It's hard to say what's causing it really, so you should try to figure why it's happening. From looking at your code I can see two things that might cause this error.
First you are using dict as a variable name, which is probably a bad idea since dict is a built-in type in python.
The other possible cause could be the way your are accessing the req dict. You are accessing the keys username, password and game_id1. If any of these should be missing in the dict it will throw a KeyError exception. I like to access dicts using req.get('username', None) instead (replace None with another default value if you prefer. Another way to tackle that issue would be try/catch exception handling.
Also, depending on your Gamer model, trying to create a using an existing username (assuming you have unique=True) would probably throw an exception as well, so you should handle that as well (I think get_or_create could be handy here).
Generally when dealing with problems of this kind, use the inspector in your browser. It lets you see all the data sent and received during the request, which means (if you're running django in DEBUG mode) you'll also get to see the default stack trace page in the inspector. It should hold some valuable indication to what's causing the issue. Another option would be to write a small middleware or enable extended error logging to log errors to strout/stderr.
I have asked a few questions about this before, but still haven't solved my problem.
I am trying to allow Salesforce to remotely send commands to a Raspberry Pi via JSON (REST API). The Raspberry Pi controls the power of some RF Plugs via an RF Transmitter called a TellStick. This is all setup, and I can use Python to send these commands. All I need to do now is make the Pi accept JSON, then work out how to send the commands from Salesforce.
Someone kindly forked my repo on GitHub, and provided me with some code which should make it work. But unfortunately it still isn't working.
Here is the previous question: How to accept a JSON POST?
And here is the forked repo: https://github.com/bfagundez/RemotePiControl/blob/master/power.py
What do I need to do? I have sent test JSON messages n the Postman extension and in cURL but keep getting errors.
I just want to be able to send various variables, and let the script work the rest out.
I can currently post to a .py script I have with some URL variables, so /python.py?power=on&device=1&time=10&pass=whatever and it figures it out. Surely there's a simple way to send this in JSON?
Here is the power.py code:
# add flask here
from flask import Flask
app = Flask(__name__)
app.debug = True
# keep your code
import time
import cgi
from tellcore.telldus import TelldusCore
core = TelldusCore()
devices = core.devices()
# define a "power ON api endpoint"
#app.route("/API/v1.0/power-on/<deviceId>",methods=['POST'])
def powerOnDevice(deviceId):
payload = {}
#get the device by id somehow
device = devices[deviceId]
# get some extra parameters
# let's say how long to stay on
params = request.get_json()
try:
device.turn_on()
payload['success'] = True
return payload
except:
payload['success'] = False
# add an exception description here
return payload
# define a "power OFF api endpoint"
#app.route("/API/v1.0/power-off/<deviceId>",methods=['POST'])
def powerOffDevice(deviceId):
payload = {}
#get the device by id somehow
device = devices[deviceId]
try:
device.turn_off()
payload['success'] = True
return payload
except:
payload['success'] = False
# add an exception description here
return payload
app.run()
Your deviceID variable is a string, not an integer; it contains a '1' digit, but that's not yet an integer.
You can either convert it explicitly:
device = devices[int(deviceId)]
or tell Flask you wanted an integer parameter in the route:
#app.route("/API/v1.0/power-on/<int:deviceId>", methods=['POST'])
def powerOnDevice(deviceId):
where the int: part is a URL route converter.
Your views should return a response object, a string or a tuple instead of a dictionary (as you do now), see About Responses. If you wanted to return JSON, use the flask.json.jsonify() function:
# define a "power ON api endpoint"
#app.route("/API/v1.0/power-on/<int:deviceId>", methods=['POST'])
def powerOnDevice(deviceId):
device = devices[deviceId]
# get some extra parameters
# let's say how long to stay on
params = request.get_json()
try:
device.turn_on()
return jsonify(success=True)
except SomeSpecificException as exc:
return jsonify(success=False, exception=str(exc))
where I also altered the exception handler to handle a specific exception only; try to avoid Pokemon exception handling; do not try to catch them all!
To retrieve the Json Post values you must use request.json
if request.json and 'email' in request.json:
request.json['email']