I'm using the below code to display an unauthorized message in JSON:
def render_unauthorized
# Displays the Unauthorized message since the user did
# not pass proper authentication parameters.
self.headers['WWW-Authenticate'] = 'Token realm="API"'
render json: {
error: {
type: "unauthorized",
message: "This page cannot be accessed without a valid API key."
}
}, status: 401
end
Which outputs:
{"error":{"type":"unauthorized","message":"This page cannot be accessed without a valid API key."}}
So my question is this: Is there a way to pretty print this message (WITHOUT putting it in a separate view and using some 3rd party gem).
Edit: What is pretty print?
Properly spaced, and well .. pretty. Here's the output I'd like to see:
{
"error": {
"type": "unauthorized",
"message": "This page cannot be accessed without a valid API key."
}
}
Solution
Using #emaillenin's answer below worked. For the record, here's what the final code looks like (since he hadn't included the whole thing):
def render_unauthorized
# Displays the Unauthorized message since the user did
# not pass proper authentication parameters.
self.headers['WWW-Authenticate'] = 'Token realm="API"'
render json: JSON.pretty_generate({ # <-- Here it is :')
error: {
type: "unauthorized",
message: "This page cannot be accessed without a valid API key."
}
}), status: 401
end
Use this helper method built into JSON.
JSON.pretty_generate
I just tried and it works:
> str = '{"error":{"type":"unauthorized","message":"This page cannot be accessed without a valid API key."}}'
> JSON.pretty_generate(JSON.parse(str))
=> "{\n \"error\": {\n \"type\": \"unauthorized\",\n \"message\": \"This page cannot be accessed without a valid API key.\"\n }\n}"
If you (like I) find that the pretty_generate option built into Ruby's JSON library is not "pretty" enough, I recommend my own NeatJSON gem for your formatting.
To use it gem install neatjson and then use JSON.neat_generate instead of JSON.pretty_generate.
Like Ruby's pp it will keep objects and arrays on one line when they fit, but wrap to multiple as needed. For example:
{
"navigation.createroute.poi":[
{"text":"Lay in a course to the Hilton","params":{"poi":"Hilton"}},
{"text":"Take me to the airport","params":{"poi":"airport"}},
{"text":"Let's go to IHOP","params":{"poi":"IHOP"}},
{"text":"Show me how to get to The Med","params":{"poi":"The Med"}},
{"text":"Create a route to Arby's","params":{"poi":"Arby's"}},
{
"text":"Go to the Hilton by the Airport",
"params":{"poi":"Hilton","location":"Airport"}
},
{
"text":"Take me to the Fry's in Fresno",
"params":{"poi":"Fry's","location":"Fresno"}
}
],
"navigation.eta":[
{"text":"When will we get there?"},
{"text":"When will I arrive?"},
{"text":"What time will I get to the destination?"},
{"text":"What time will I reach the destination?"},
{"text":"What time will it be when I arrive?"}
]
}
It also supports a variety of formatting options to further customize your output. For example, how many spaces before/after colons? Before/after commas? Inside the brackets of arrays and objects? Do you want to sort the keys of your object? Do you want the colons to all be lined up?
Using the aligned option would allow your output to look like this:
{
"error": {
"type" : "unauthorized",
"message" : "This page cannot be accessed without a valid API key."
}
}
Related
I'm building an API with Ruby on Rails. Because of that, I can't force the params to follow sone restriction.
Currently, I'm having an error with params that contained a Windows newline, because the newline isn't escaped.
The request body looks like below:
{
"name": "Jon Do",
"address": "6th Street\r\nDistrict City\r\nNation"
}
And it generated JSON::ParserError: 784: unexpected token
How to correctly process that request so params[:address] can be called without error?
When passing the data from front-end, make it JSON.stringify, and parse from back-end.
#Front-end
address: JSON.stringify(objects)
#Back-end
JSON.parse(params[:address])
I would like to put a Markdown code block in the description of my API but the Swagger UI seems to be reading as though it was a single line code snippet. I currently have:
description: |
This API was created to allow interaction with the Image Status Database (ISD)
## Requests
## Responses
In the case of a successful response, you will always receive a `data` key
that contains your data.
```
{
"meta": {
"code": 200
},
"data": {
...
},
"pagination": {
"next_url": "...",
"next_max_id": "13872296"
}
}
```
This gets displayed as:
The Swagger Editor, however, displays the proper code block:
Is this not supported by the Swagger UI?
The code block formatting issue was fixed in Swagger UI 3.22.0 and Swagger Editor 3.6.26. Code blocks are displayed properly in these versions:
Note the line break between "a data key" and "that contains" in the text - it is caused by the | literal block style, which preserves the line breaks in YAML multi-line strings. To avoid that line break you can either 1) remove it in your YAML, or 2) use the > folded style and also indent the code block (to prevent it from being folded), as shown below:
description: >
This API was created to allow interaction with the Image Status Database (ISD)
## Requests
## Responses
In the case of a successful response, you will always receive a `data` key
that contains your data.
```
{
"meta": {
"code": 200
},
"data": {
...
},
"pagination": {
"next_url": "...",
"next_max_id": "13872296"
}
}
```
First time trying to use the Ruby AWS ADK V2 and I am trying to format the data i am getting back and it seems quiet hard getting it into useable format.
All I want to do is get a list of Hosted Zones and display in a table.
I have a helper that has:
def hosted_zones
r53 = Aws::Route53::Client.new
#convert to hash first so we can parse and covert to json
h = (r53.list_hosted_zones).to_hash
j = JSON.parse((h.to_json))
end
which then returns me the following JSON:
{
"hosted_zones": [{
"id": "/hostedzone/Z1HSDGASSSME",
"name": "stagephil.com.",
"caller_reference": "2016-07-12T15:33:45.277646707+01:00",
"config": {
"comment": "Private DNS zone for stage",
"private_zone": true
},
"resource_record_set_count": 10
}, {
"id": "/hostedzone/ZJDGASSS0ZN3",
"name": "stagephil.com.",
"caller_reference": "2016-07-12T15:33:41.290143511+01:00",
"config": {
"comment": "Public DNS zone for stage",
"private_zone": false
},
"resource_record_set_count": 7
}],
"is_truncated": false,
"max_items": 100
}
To which I am running a really but while statement to interact through all the hosted_zone entries into a table.
Is this the best way to get the response or can you request the response to be json already?
Why are you converting a hash to JSON, only to convert it to a hash again? JSON.parse(some_hash.to_json) will just give you some_hash.
That being said, I don't think it is possible to get JSON directly from AWS, mainly due to the fact that their API responds with XML. I think that your solution is ideal if that's all you're doing, but if you want, you can make a request with an HTTP client and then take the XML that you receive and use something like ActiveSupport's Hash.from_xml to create a hash that you can then convert to JSON.
I am using an API for my university project, which sends me multiple responses which are all valid JSON.
Both are treated as string in response.body so I need to parse them into JSON or ruby object.
The first one passes through the JSON parser but fails if I use eval which returns a ruby object
{
apiCode: "SUCCESS",
friendlyMessage: "All information saved successfully"
}
Second one passes through eval and gives me a valid Ruby object but fails as a valid JSON.
{
apiCode: "SUCCESS_WITH_ERRORS",
friendlyMessage: "Some of the information was not processed",
successfulIds: [
{
ssid: "My Test 1",
bssid: "2d:8c:e5:5c:bb:b9"
},
{
ssid: "My Test 2",
bssid: "2a:7d:a4:5c:aa:a7"
}
]
Regards,
Babar
Running both your JSON blobs through both JSON Lint and Ruby's JSON library results in an error.
The error for the first one is
Error: Parse error on line 1:
{ apiCode: "SUCCESS",
--^
Expecting 'STRING', '}', got 'undefined'
and for the second one is
Error: Parse error on line 1:
{ apiCode: "SUCCESS_WI
--^
Expecting 'STRING', '}', got 'undefined'
The errors suggest that your JSON should look like (I'm showing the first one here)
{
"apiCode": "SUCCESS",
"friendlyMessage": "All information saved successfully"
}
(which parses successfully everywhere).
Using eval for parsing data coming from some external source is a bad idea, because opens a direct code execution vulnerability.
For parsing JSON there's a build-in parser:
require 'json'
ruby_object = JSON.load(your_json_string)
For more speed, if you need it, use a dedicated json parser gem like oj directly or through MultiJson gem.
Also your second json is missing the final } so is not valid, also hash keys in json are supposed to be in "
I'm trying to use the create_flow endpoint to the Survey Monkey API. It is sending back a status 3 message with the following error:
additional properties not defined by 'properties' are not allowed in field '_data'
I'm able to do successfully use all other API endpoints and have a valid API key and durable OAuth token.
Here's an example JSON body that I'm sending to: https://api.surveymonkey.net/v2/batch/create_flow?api_key=apikeyhere
{
"survey": {
"template_id": "566",
"survey_title": "test1",
"collector": {
"type": "email",
"name": "collector1",
"recipients": [
{
"email": "email#example.com"
}
]
},
"email_message": {
"reply_email": "myemail#example.com",
"subject": "this is a test"
}
}
Note: JSON formatting here is being generated automatically using RJSONIO
Any ideas what might be causing the error? It seems like all fields are correctly named and where they're supposed to be, so I'm not sure what the problem is.
It's a bad error message unfortunately - it's a known issue. It means you are providing extra keys that are not part of the create_flow schema.
The issue here is that the "email_message" and "collector" keys have been nested inside of "survey", instead of being in the main JSON body like the "survey" key. Move them out a level and it should work.