Rails 3: How to return errors in a JSON request? - json

How can I return a 800, 404, etc error when a user makes a JSON/XML request to my API?
I've tried
error 404, {:error => "ERror".to_json }
with no success.
Also, I've tried to put a "respond_to" but it doesn't work as well (it duplicates the respond_to and gives error).
Thanks

The same way you return such errors with html, it's part of the HTTP Header.
render json: #myobject, status: :unprocessable_entity
Update, response to comment:
You can get all the status codes from Rack. Rails passes the symbolized status to Rack
Rack::Utils.status_code(options[:status])
which simply matches the symbol to the list of status (the strings are converted to symbols)
Here is the smoking fresh list: https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L575-L638
Scroll a bit lower and you'll see the status_code method. It's fun to read the source code!

Related

Fiware Orion batch duplicate

I'm using APPEND_STRICT, but having trouble understanding a certain concept.
Example, I have a single entity in Fiware Orion(already created) and want to create let's say 1000 entities in batch using APEND_STRINCT(v2/op/update).
In 1000 entities there is 1 duplicate(an entity I mention that is already in Orion).
So is this correct, Orion will throw error 422 without any information in term of the id of an entity that already exists, error talk about attributes of the entity (I understand why it is the concept of APPEND_STRICT) but showing it would really help.
And another part is if the entity which is duplicate was on position 400 then Orion send error but continue to write remaining entities, this is really hard to manage because I cannot know when a total write is done and have to show some response while Orion still works on them in the background.
Are my assumptions correct and can be something done to avoid this, something I failed to notice.
Thanks.
Edit
Error message:
{ error: 'Unprocessable',
description: 'one or more of the attributes in the request already exist:
[ family, serialNumber, refSortingType, description, refType, storedWasteOrigin, location, address, fillingLevel, cargoWeight, temperature, methaneConcentration, regulation, responsible, owner, dateServiceStarted, dateLastEmptying, nextActuationDeadline, actuationHours, openingHours, dateLastCleaning, nextCleaningDeadline, refDepositPointIsle, status, color, image, annotations, areaServed, dateModified, refDevice ]' } } }
Example request:
{ method: 'POST',
headers:
{ 'Content-Type': 'application/json',
'Fiware-Service': 'waste4think',
'Fiware-ServicePath': '/d',
'X-Auth-Token': 'DssfKZe82e1dyJof416EmrQPdFQ3QK1' },
uri: 'http://localhost:1026/v2/op/update',
body: { actionType: 'APPEND_STRICT', entities: [Array] }
{"actionType":"APPEND_STRICT","entities":[{"id":"xxx","type":"xxx","family":{"value":"Agent","type":"String","metadata":{}},"serialNumber":{"value":"","type":"String","metadata":{}},"refSortingType":{"value":"SortingType:2","type":"String","metadata":{}},"description":{"value":"","type":"String","metadata":{}},"refType":{"value":"DepositPointType:0","type":"String","metadata":{}},"storedWasteOrigin":{"value":"","type":"String","metadata":{}},"location":{"value":{"type":"Point","coordinates":[xxx]},"type":"geo:json"},"address":{"value":"xxxxx.","type":"String","metadata":{}},"fillingLevel":{"value":0,"type":"Float","metadata":{"unit":{"value":"C62","type":"String"}}},"cargoWeight":{"value":0,"type":"Float","metadata":{"unit":{"value":"KGM","type":"String"}}},"temperature":{"value":0,"type":"Float","metadata":{"unit":{"value":"CEL","type":"String"}}},"methaneConcentration":{"value":0,"type":"Float","metadata":{"unit":{"value":"59","type":"String"}}},"regulation":{"value":"Municipal association","type":"String","metadata":{}},"responsible":{"value":"","type":"String","metadata":{}},"owner":{"value":"xxx","type":"String","metadata":{}},"dateServiceStarted":{"value":"","type":"String","metadata":{}},"dateLastEmptying":{"value":"","type":"String","metadata":{}},"nextActuationDeadline":{"value":"","type":"String","metadata":{}},"actuationHours":{"value":[],"type":"List","metadata":{}},"openingHours":{"value":[],"type":"List","metadata":{}},"dateLastCleaning":{"value":"","type":"String","metadata":{}},"nextCleaningDeadline":{"value":"","type":"String","metadata":{}},"refDepositPointIsle":{"value":"","type":"String","metadata":{}},"status":{"value":"ok","type":"String","metadata":{}},"color":{"value":"","type":"String","metadata":{}},"image":{"value":"","type":"String","metadata":{}},"annotations":{"value":"","type":"String","metadata":{}},"areaServed":{"value":"","type":"String","metadata":{}},"dateModified":{"value":"","type":"String","metadata":{}},"refDevice":{"value":"","type":"String","metadata":{}}}]}
As for the request, I split the post part and body part. As you can see by error msg is not possible to know what entity caused this
I think the functionality is as you describe. Orion responses with a list of the attributes that already exist but not to which entity they belong. A response like this could be probably more useful:
'one or more of the attributes in the request already exist:
entity23: [ family, serialNumber], entity 42: [refSortingType, description]'
with some capping (e.g. as much as 20 entities) to preclude too bigs responses.
If you think implementing something like that could be insteresting, please create a new issue in the Orion repository about it, please.
Some additional comments:
APPEND_STRICT is deprecated. The right keyword is appendStrict.
Regarding "Orion send error but continue to write remaining entities, this is really hard to manage because I cannot know when a total write is done and have to show some response while Orion still works on them in the background". Orion doesn't response until it finishes to process the whole batch in the POST /v2/op/entity request. So your REST client can be sure that when the response is received everything has been processed (although that processing could involve errors due to duplicated attributes in some entities, as we have been discussing). Have you experience a different behaviour? In that case, how did you get it? (it Orion is behaving that way it could be a bug and I'd like to know about in order to debug it).

Cherrypy assignment confusion

I am a student and struggling with an assignment. Our professor wants us to create a server using cherrypy, and her test script to test the server's functionality sends json data to our sever and we must decode it. She gave us a line to help us, yet I have no idea how to use it. This is what it says in my code. What does the cherrypy.request line do, and how does it accept incoming json data? Thanks :-)
def GET(self):
output = { 'result': 'success'}
#this is the line she wants us to use below
body = cherrypy.request.body.read(int(cherrypy.request.headers['Content-Length']))
try:
body = json.loads(body)
except KeyError as ex:
output['results'] = 'error'
output['message'] = str(ex)
return json.dumps(body)

Meteor.http.call (call URL API)

so I'm trying to make a call to a bible verse API in my Meteor application. I made a template with name="display", with a simple {{checkitout}} in the template.
Then for the template, I tried to make the call in its corresponding helper. It looks like this (in coffeescript, but Javascript readers should understand as well):
#Template.display.helpers
checkitout:->
result = Meteor.http.call("GET","http://labs.bible.org/api/passage=john%203:2&type=json")
console.log(result)
The URL is a JSON of a bible verse, but the problem is, the Meteor.http.call requires a third argument, a "callback" (because this is in the client folder). I read some documentation + examples and have no idea what it means.
Also, if I call it like this, is result exactly the JSON file, or do I need to fit it within a new hash? And what does a callback mean? Can someone give me an example?
As helpers are synchronous and API calls are not, you need to store the call result in a reactive variable and return it from the helper:
verse = "Loading..."
verseLoaded = false
verseDep = new Deps.Dependency()
Template.Display.checkItOut = ->
verseDep.depend()
unless verseLoaded
verseLoaded = true
Meteor.http.get "...", (error, result) ->
verse = "..."
verseDep.changed()
verse
On the client, the callback is required as you said. So this is something you could do to query an API and display the JSON result:
Template.Display.helpers
checkItOut: ->
Meteor.http.get 'https://graph.facebook.com/facebook', (error, result) ->
if not error
console.log result # display the the open graph result
Note 1: To use these functions, you need to add the HTTP package to your project with $ meteor add http. You can find further information in the documentation.
Note 2: In your situation, you cannot make an API call client-side due to the Access-Control-Allow-Origin Policy. So, the solution would be to use a method and make the call server-side.
# Client-side
Template.Display.helpers
checkItOut: ->
Meteor.call 'getBibleText', (error, result) ->
if not error
console.log result
# Server-side (server directory)
Meteor.methods
'getBibleText': ->
result = HTTP.get 'http://labs.bible.org/api/?passage=john%203:2&type=xml'
return result

jQuery-tokeninput not showing my search results

I am using the jquery-tokeninput and is not able to get it to work, the ajax call is not entering the success method when the result contains a list of results.
I use jQuery version 1.9.1 and the tokeninput version 1.6.1
I am using this html, and jquery script:
<input type="text" class="selector" name="users">
$('.selector').tokenInput("/event/usersearch", { method: 'POST', minChars: 2 });
When I test it I get the following response:
Click on the edit field to provide it with focus.
a dropdown is shown with the text "Type in a search term"
Press the letter u.
the dropdown disappears as expected as i set it to search after to
chars
press the letter p.
the dropdown comes back with the text "Searching..."
a request is sent to the server with the query string "up"
the server respond with this (Content-Type:
application/json;charset=utf-8)(55 bytes):
[{id:2, name:'Superuser'},{id:3, name:'Bo Superduper'}]
but the dropdown is still showing "Searching..."
press the letter x
a request is set to the server with the query string "upx"
the server responds with(2 bytes): []
the dropdown changes to "No results"
So when the server does return an empty list all works fine, but if records are returned the userinterface is not showing the items.
I tried with both GET and POST requests...
I tried to return [{id:2, name:"Superuser"},{id:3, name:"Bo Superduper"}] but with same result
I tried to return [{id:"2", name:"Superuser"},{id:"3", name:"Bo Superduper"}] but with same result
I tried to return [{"id":"2", "name":"Superuser"},{"id":"3", "name":"Bo Superduper"}] but with same result
Within the tokeninput java script file, I set a breakpoint at the first line in the ajax success function:
// Attach the success callback
ajax_params.success = function(results) {
cache.add(cache_key, $(input).data("settings").jsonContainer ? results[$(input).data("settings").jsonContainer] : results);
And it is not called on the requests that contains items, but the requests that returns an empty lists will be called. This explains why the "Searching..." remains on, and only changes when empty lists are returned.
All requests return http status 200 OK.
From the byte count the utf-8 is the same as ascii, so it shouldnt be a encoding problem...
So the ajax request is sent, and returns but the success method is not called?
How are you currently returning your JSON? If the ajax call isn't calling success I'd guess your response is somehow malformed. For example, of the 4 versions you've tried - only the last one is valid. JSON requires double quotes, and also attribute names to be in quotes.
I'd suggest automatically generating your JSON string at source, which should ensure you get the correct header types and the like too. If it's php, you can use:
echo json_encode(//PHP Assoc Array Here);

Avoiding double render error when rendering a 500 screen from original render exception

In my Application controller, I have this to catch all otherwise uncaught exceptions...
if Rails.env != "test"
rescue_from Exception, :with => :render_500
end
It nicely catches exceptions and calls my "render_500" action, which logs the exception to the database and then renders a custom 500 page that includes a reference GUID for the exception (so I can look up details later).
The problem I'm running into is that if the exception caught occurred while rendering a page (e.g., bad code in a view, undefined variable referenced in a view), I end up triggering a second exception because of a double render error.
Thoughts on how to avoid this double render error on rendering the 500 page?
The way to avoid a double render error by rendering a second time seems to be to check if there already exists a response body...
render unless response_body
Since, if I understand correctly you want the second render to replace the first you might try replacing the existing response_body with your own. Since response_body is an array of strings you could probably use render_to_string then replace the response body like:
def render_500
...stuff...
response = render_to_string "myController/view"
status = 500
unless response_body
render :inline=> response
else
response_body = [response]
end
end
Plus whatever other headers you needed to adjust. This isn't tested and feels a bit unpleasant but I think it should work. I'd be happy to hear if there's a cleaner way.