I know that there are nice modules (like the validator-collection) that can check if a JSON is valid. But in my case, I want to achieve this with the built-in Flask capabilities: is_json() and get_json().
This is what I have tried:
import flask
def get_json_data():
if flask.request.is_json():
try:
data = flask.request.get_json()
except(ValueError):
# get_json failed, return None
# handle ValueError
else:
# is_json failed, return None
# handle ValueError
After reading the docs, I could only find the ValueError exception being raised. If that is indeed the only exception, is my approach above correct in handling it and making sure that a data will hold JSON data only when a valid JSON request has been made?
The documentation states that .is_json() only checks if the request has a Content-Type that would indicate that the request contains JSON data.
property is_json
Check if the mimetype indicates JSON data, either application/json or application/+json*.
It does not check whether the request data is actually JSON, so this check's usefulness is limited. When the client sends JSON but does not set an appropriate Content-Type header, or sets the header but sends invalid JSON, you learn nothing from .is_json().
However, .get_json() does a "contains valid JSON" check: It tries to parse the request data as JSON, and either that works, in which case it returns the data, or it fails, in which case it throws an error. By default, .get_json() internally calls .is_json() anyway.
For what you want to do, I would say this is sufficient.
def get_json_data():
data = flask.request.get_json()
If parsing is unsuccessful, there is no error thrown (compare werkzeug docs). Instead "Bad Request" is returned to the client. If you want to change that behavior, override the Request.on_json_loading_failed() method with your own version.
Related
I'm not sure whether I should include success message in the response when I create an API server.
Like when you PUT something to the API server and the backend creates something successfully, you can get a response with 201 status code.
Does the API server should include a message like:
{
"message": "Successfully created."
}
as JSON in the response?
I agree with VoiceOfUnreason: it not is mandatory, but I usually return
{"status":"ok"}
If I need to return some content
{"status":"ok","result":{.....}}
And, in case an error occurs, I still prefer to return a 200 handling the error at the application level
{"status":"ko","errorMessage":"Something went wrong!"}
Fabio
Should REST API always return response with a message?
It's not required - we have 204 (No Content) and 205 (Reset Content) in the standard because there are cases where a response without a body makes sense.
But in common cases where we are sending a 200/201, I would expect to see a response body describing the status of the action
The 201 response content typically describes and links to the resource(s) created.
No for example, for 204 responses we must not include message body. {success: true} is redundant.
In practice (or should I say in later version of jquery), empty response for application/json content type raises error. I kind of understand the argument that because it's application/json it must have a valid json body. So, empty response for application/json content type would be 'null' or '{}' which are valid json.
There's another way which should work for jquery, that is not returning application/json for empty responses. Just use text/plain or something and make sure client can handle that type.
I'm using AFNetworking 2.3 API to fetch currency exchange rates which returns JSON. In addition to HTTP the API also supports HTTPS. I'm using a subclass of AFHTTPSessionManager and set the response serializer to AFJSONResponseSerializer.
If I use HTTP everything works as expected, however once I use HTTPS, I receive the following error
Error Domain=NSCocoaErrorDomain Code=3840 "The data couldn’t be read
because it isn’t in the correct format." (JSON text did not start with
array or object and option to allow fragments not set.)
UserInfo=0x60000046c700 {NSDebugDescription=JSON text did not start
with array or object and option to allow fragments not set.}
I checked the response data and it appears identical to the HTTP response. Also the response code is 200 and the header indicates
"Content-Type" = "application/json; charset=utf-8";
If I entry the url directly into safari the data appears as expected. I also tried setting the reading options of the response serializer to NSJSONReadingAllowFragments, but no change.
Is this a server side issue? What else could I do to debug this?
above code from the website_mail module controller file email_designer.py file
class WebsiteEmailDesigner(http.Controller):
#http.route('/website_mail/email_designer/<model("email.template"):template>/', type='http', auth="user", website=True, multilang=True)
def index(self, template, **kw):
values = {
'template': template,
}
return request.website.render("website_mail.designer_index", values)
#http.route(['/website_mail/snippets'], type='json', auth="user", website=True)
def snippets(self):
return request.website._render('website_mail.email_designer_snippets')
which situation we are using type="json" and type="http" and why..??
Basically type="json" is used to pass data from controller where as type="html" is for responding over http request.
For example from your above code:
the url "/website_mail/email_designer//" will respond towards any particular http request and route to its web page where as the url "/website_mail/snippets" will just pass json data to its rendered template but there is no physical webpage related to this url.
Methods that received JSON can be defined by passing 'json' to the type argument of http.route(). The OpenERP Javascript client can contact these methods using the JSON-RPC protocol. JSON methods must return JSON. Like the HTTP methods they receive arguments as named parameters (except these arguments are JSON-RPC parameters).
#http.route('/division', type="json")
def division(self, i, j):
return i / j # returns a number
Both of them are about communication between client and server. HttpRequest communicates trough the well known GET and POST methods. That means the following:
The client send a request encoded in the url (GET method) or in the http body (POST method)
The server returns an object corresponding to the request. Could be an html page, PNG image, CSS file, JavaScript, XML encoded data or whatever.
JsonRequest is an implementation of another protocol for client/server communication - JSON-RPC 2.0. You may want lo took here form more information. It's a remote procedure call (RPC) protocol which means that it allows the client to initiate the execution of some method on the server passing some arguments to this method. In response the client gets some data as a result of the method invocation.
EDIT - some more words about the decorators #openerpweb.jsonrequest and #openerpweb.httprequest
Some methods are decorated with the #openerpweb.jsonrequest decorator, other methods - with the #openerpweb.httprequest. This means nothing else but that the first group of methods will be available for execution trough the JSON RPC protocol and the second group will be accessible trough the pure HTTP protocol.
Now, what is the difference? I do we need both jsonrequest and httprequest? Let simplify it like this: JSON is more suitable for executing methods on the server and obtain results. HTTP is simpler and easier to use when all we what is to access some resource on the server.
Let's 'decorate' this with some examples for clarity. Take a look at the following method of the web.controllers.main.Export class:
#openerpweb.jsonrequest
def formats(self, req):
""" Returns all valid export formats
:returns: for each export format, a pair of identifier and printable name
:rtype: [(str, str)]
"""
...
This method accepts some arguments and returns a list (Python list object) containing all known export formats. It will be called in a programmatic way in some python code on the client side.
On the other side are the 'http' methods - like the method css() of the web.controllers.main.Web class:
#openerpweb.httprequest
def css(self, req, mods=None):
....
All this method does is to return a CSS file to the client. It's a simple action like accessing an image, a HTML web page or whatever other resource on the server. The resource we are returning here is nothing complicated as a Python list as in the previous example. We don't need a special format to encode it additionally. So we don't need additional data encoding format as JSON and remote procedure call protocol as JSON RPC.
type="json":
it will call JSONRPC as an argument to http.route() so here , there will be only JSON data be able to pass via JSONRPC, It will only accept json data object as argument.
type="http":
As compred to JSON, http will pass http request arguments to http.route() not json data.
Examples
#http.route('demo_html', type="http") // Work Pefrect when I call this URL
def some_html(self):
return "<h1>This is a test</h1>"
#http.route('demo_json', type="json") // Not working when I call this URL
def some_json(self):
return {"sample_dictionary": "This is a sample JSON dictionary"}
I'm building an application that communicates with a django backend using json-rpc. So far all has been working well. However I've found an anomaly in sending " ". As far as I know the request works fine, however django interprets the response badly. I've reproduced a simplified request and response below:
Request:
{"jsonrpc":"2.0","id":"1","method":"test","params":
{"id":"80","name":"tests","introduction":"hello there"}}
Django receives:
<QueryDict:u'{"jsonrpc":"2.0","id":"1","method":"test","params":
{"id":"80","name":"tests","introduction":"hello ': [u''], u'nbsp': [u''], u'there"}}': [u'']}>
Expected response:
<QueryDict: {u'{"jsonrpc":"2.0","id":"1","method":"test","params":
{"id":"80","name":"tests","introduction":"hello there"}}': [u'']}>
It seems like django interprets the & and the ; as special characters and so creates an unexpected dictionary in its request.POST variable.
What do I need to do to make sure that the json string doesn't get malformed? I have tried encoding it using the php htmlspecialchars() method, but since that doesn't remove the '&' the problem persists.
Any help will be much appreciated.
Django is handling the (POST?) request by decoding the body (your json string) as if it were a query string, and not a json.
Within a query string, & and ; denote the end of a key:value pair. Splitting up your request body on those two characters yields the key:value pairs you see in the Django QueryDict.
You need to get hold of the POST request body and explicitly decode it to a dict yourself using either the standard lib json, or simplejson module.
I have little experience with Django specifically, but I imagine that somewhere in your view handler you would do something akin to:
try:
data = json.loads(requesst.raw_post_data)
## work with the data...
except ValueError:
## do something...
No doubt Django provides a way to move this json handling out of your views, and to somewhere more suitable.
We are in the middle of a ongoing discussion about how to handle REST exceptions.
Response Content type : JSON
Two solutions we have:
Throw all the unchecked exceptions as a JSON response.
Send Request Invalid Response code.
Arguments:
When its a error, why return JSON? Just send a invalid response code.
Counter Argument:
Response code are too technical to handle for normal developers.
Whats your say??
For a JSON API I recently developed I do both. I always respond with valid JSON (well, assuming I respond at all). If I detect an invalid request, I use status 400. If I detect a server error (which I don't believe is caused by an invalid request), I use a 5xx status. The JSON object contains a special key that is only set for errors, with a string value.
I think this is a good solution that respects REST principles, and can be used in multiple ways. The same solution is used by some other JSON APIs, such as Yahoo Search. Try http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=YahooDemo&output=json .
Use error codes like for HTTP. So 50* for any exception cause by some internal problem. And 40* for bad arguments. Avoid using your own defined codes as far as its possible. The idea is to have a "uniform" interface.
In general.
204 for success without sending any content
200 for success with a json representation of the resource
And if its not a successful operation return appropriate response code. You can choose to optionally return a json. To simplify things you can have a common format (json) for all error responses.
http://en.wikipedia.org/wiki/REST is a must read before you freeze on your api specs.