How to convert a stream into an object in Ruby - json

I am attempting to make a PUT fetch request from my jQuery file. The server giving me a 500, as the fetch is not able to be used by my controller.
This is the stream that is being sent to my .rb file in the form of request.body:
request.body == #<StringIO:0x00005597c3b69fa8>
request.body.string == "{\"name\":\"New School\",\"office_id\":2,\"inactive\":false}"
I have tried..
load(request.body.string)
But this returns a load error:
LoadError: cannot load such file -- {"name":"New School","office_id":2,"inactive":false}
Also..
parse(request.body.string)
which results in
undefined method `parse' for #<CrEventsApp:0x00005597c3bbf098>
Is there a method that will parse this information back into a hash? I can parse through the string myself with some regex and .split() to get the data into a useable format, but I would like a more concise and robust solution.

JSON.parse should do the trick:
JSON.parse(request.body.string)
=> {"name"=>"New School", "office_id"=>2, "inactive"=>false}

Related

Node Rest Client Response Error

Can I handle a non-JSON response in node-rest-client POST method?
This is the error and response i'm getting:
response: [PURGED], error: [SyntaxError: Unexpected token P in JSON at
position 0]
Can I somehow avoid getting an error? The function does what is requested.
I suppose creating a custom parser is a solution? I don't understand how to achieve it though.
You need to add a "mimetypes" attribute to your client options.
For example, something like this should enable you to handle XML as well as JSON responses:
const Client = require('node-rest-client').Client;
var client = new Client({mimetypes:{
json:["application/json","application/json;charset=utf-8"],
xml:["application/xml","application/xml;charset=utf-8"]
}});
client.post(...)

Error with node-redis: Deprecated: The SET command contains a argument of type Object

I'm using the connect-redis-crypto module (https://github.com/jas-/connect-redis-crypto
) which is built for encrypting redis session data on top of connect-redis(https://github.com/tj/connect-redis). My redis version is 3.2.8.
I am running into error node-redis: Deprecated: The SET command contains a argument of type Object. Based on the larger error message, it seems to come from trying to parse the string [object Object] when it is not a JSON string. I put nested objects that hold user information on req.session which directly gets stored (and ideally encrypted) in redis.
From some sources I learned nested objects in Redis are not allowed which might cause this error, but I believe this library stores data as JSON to allow for nested objects. connect-redis works fine for me, but when this connect-redis-crypto library tries to JSON parse encrypted data it throws me this particular error.
Would really appreciate your help!
node_redis: Deprecated: The SET command contains a argument of type Object.
This is converted to "[object Object]" by using .toString() now and will return an error from v.3.0 on.
Please handle this in your code to make sure everything works as you intended it to.
8 May 18:24:48 - ---NEW REQUEST---
REQUEST : GET /api/somePath/client
QUERY : {}
BODY : {}
data [object Object]
err SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse (<anonymous>)
at Command.callback (/Users/Documents/web-AOT/server/node_modules/connect-redis-crypto/lib/connect-redis.js:262:35)
at normal_reply (/Users/Documents/web-AOT/server/node_modules/redis/index.js:721:21)
at RedisClient.return_reply (/Users/Documents/web-AOT/server/node_modules/redis/index.js:819:9)
at JavascriptRedisParser.returnReply (/Users/Documents/web-AOT/server/node_modules/redis/index.js:192:18)
at JavascriptRedisParser.execute (/Users/Documents/web-AOT/server/node_modules/redis-parser/lib/parser.js:560:12)
at Socket.<anonymous> (/Users/Documents/web-AOT/server/node_modules/redis/index.js:274:27)
at emitOne (events.js:96:13)
at Socket.emit (events.js:189:7)
at readableAddChunk (_stream_readable.js:176:18)
at Socket.Readable.push (_stream_readable.js:134:10)
at TCP.onread (net.js:551:20)
The solution is here
You have to wrap your object in JSON.stringify and then remember to JSON.parse the response when you query the key later.
// set
client.set(
"key",
JSON.stringify(
{
example: {
field: "testing",
field1: 333
},
field: 123
}, () => {}
)
);
// get
client.get("key", (err, data) => {
console.log(JSON.parse(data));
});
Actually I was able to fix the error by making tweaks via the forked library. :)
If anyone ever runs into this error...
https://github.com/rjlee7/connect-redis-crypto

How Can I parse out JSON in a Node-RED Function

I am working with Node-RED in Bluemix for IoT.
How can I parse out the individual pieces of information (like the cmdmsg and the tempr) in a function node so I can use it in other nodes in the flow?
I'm getting an error when I try (see below)
I am receiving the JSON complete message object (from an IoT in Node) that I see in my "debug" node when I set it to look at the complete message object. see the object below.
It appears to me that the JSON is formatted correctly.
I tried putting the following in the function node, but I'm getting an error that says "TypeError: Cannot read property 'tempr' of undefined"
Here is what the function parameter is:
return {payload:msg.payload.d.tempr};
and here is the message object
{
"topic": "iot-2/type/Arduino-tempsensor/id/FFFFFFFFFFFF/evt/status/fmt/json",
"payload": "{\n\"d\": {\n\"myName\": \"Arduino CF\",\n\"cmdmsg\": \"Weekly\",\n\"tempr\": -3,\n}\n}",
"deviceId": "FFFFFFFFFFFF",
"deviceType": "Arduino-tempsensor",
"eventType": "status",
"format": "json",
"_msgid": "ffffffff.55555"
}
note: I obfuscated the device ID (mac address) and msgid
Any ideas on how to parse the data out and why I'm getting an error?
Sorry, but your JSON Payload is completely messed up, it should look like this: {"d": {"myName": "Arduino CF","cmdmsg": "Weekly","tempr": -3}}
You shouldn't see any \or \nin the payload, they look like escape characters from the client side. I also believe that the last comma after the tempr value shouldn't be there for valid JSON.
I am not an Arduino expert but I have experimented with a Raspberry Pi and the Mosquitto client, this is how I can successfully send an event to IoTF:
mosquitto_pub -h <org>.messaging.internetofthings.ibmcloud.com -p 1883 -u "use-token-auth" -P "<token>" -i d:<org>:raspi:raspi2 -t iot-2/evt/message/fmt/json -m {"d":{"text":"Hello World"}}
If the paylod is correct JSON your statement return {payload:msg.payload.d.tempr}; will work.
Have you seen this: http://www.ibm.com/developerworks/cloud/library/cl-bluemix-arduino-iot2/
The JSON string you are showing should be converted to a Javascript object before you try to access its fields. To do that is as simple as wiring the arduino output to a "JSON" node, which does the conversion for you (or throws an error if the string is not valid JSON).
Wire the output of the JSON node to a debug node, if you want to see the structure of the msg object. You can also wire it to a "change" node, if you simply want to replace the msg.payload with the temperature value, for instance. You don't need any custom javascript code in a function node to do simple changes like that.
Here is a sample flow that you can import... the arduino output string is simulated by pasting your payload into a "template" node:
[{"id":"1a79abfe.b8abb4","type":"inject","z":"58c8eb7a.5496c4","name":"send output","topic":"iot-2/type/Arduino-tempsensor/id/FFFFFFFFFFFF/evt/status/fmt/json","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":2740,"wires":[["9fc678fb.ae18e8"]]},{"id":"69e91778.e0c6e8","type":"json","z":"58c8eb7a.5496c4","name":"","property":"payload","action":"","pretty":false,"x":390,"y":2800,"wires":[["d066800f.60a9b","cf991eb1.f2a1a"]]},{"id":"9d8d7da2.2a7da","type":"debug","z":"58c8eb7a.5496c4","name":"msg string","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":610,"y":2740,"wires":[]},{"id":"9fc678fb.ae18e8","type":"template","z":"58c8eb7a.5496c4","name":"arduino string","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n \"d\": {\n \"myName\": \"Arduino CF\",\n \"cmdmsg\": \"Weekly\",\n \"tempr\": -3\n }\n}","output":"str","x":360,"y":2740,"wires":[["69e91778.e0c6e8","9d8d7da2.2a7da"]]},{"id":"d066800f.60a9b","type":"change","z":"58c8eb7a.5496c4","name":"extract tempr","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.d.tempr","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":2860,"wires":[["af730d72.2995a"]]},{"id":"af730d72.2995a","type":"debug","z":"58c8eb7a.5496c4","name":"tempr","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":630,"y":2860,"wires":[]},{"id":"cf991eb1.f2a1a","type":"debug","z":"58c8eb7a.5496c4","name":"msg object","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":610,"y":2800,"wires":[]}]
As was noted, your original JSON string was not valid, because of the trailing comma -- but it is ok to have double-quotes and newlines as long as they are escaped with a "\". When the string is parsed, they are stripped out anyway.

Send both JSON response and model in Grails

I'm new to Grails and I'm stuck up with a problem. I want to know if there is a way to send both JSON and view and model through "render" in Grails.
I'm using a jQuery Datatable to display data returned from server which is read from JSON returned by the controller. I also need to display error messages on the same view in case of validation failure in form fields. But I'm able to return either only the JSON or model and view using render. I also tried sending the JSON through model itself but it didn't work.
This is my code:-
def hierarchyBreakInstance = new HierarchyBreak(params);
String json = "{\"sEcho\":\"1\",\"iTotalRecords\":0,\"iTotalDisplayRecords\":0,\"aaData\":[]}";
hierarchyBreakInstance.errors.reject(message(code: 'hierarchyBreak.error.division.blank'));
render(view: "hierarchyBreak", model: [hierarchyBreakInstance: hierarchyBreakInstance]);
//render json;
The gsp code:-
<g:hasErrors bean="${hierarchyBreakInstance}">
<div class="errorMessage" role="alert">
<g:eachError bean="${hierarchyBreakInstance}" var="error">
<g:if test="${error in org.springframework.validation.FieldError}" > data-field-id="${error.field}"</g:if>
<g:message error="${error}"/>
</g:eachError>
</div>
</g:hasErrors>
Could you please let me know if there is a way to do this. Thanks!
You can use like this.
def hierarchyBreakInstance = new HierarchyBreak(params);
String json = "{\"sEcho\":\"1\",\"iTotalRecords\":0,\"iTotalDisplayRecords\":0,\"aaData\":[]}";
hierarchyBreakInstance.errors.reject(message(code: 'hierarchyBreak.error.division.blank'));
render(view: "hierarchyBreak", model: [hierarchyBreakInstance: hierarchyBreakInstance,json:json]);
//render json;
Assuming that you are doing a request with some parameters, and need to return if was succesfull or not, and the data to fill the table with ajax.
I will do on that way, use the statuses of the HTTP to mark if it was a problem with the validation(normally we return 400 Bad Request and the message)
Example :
return ErrorSender.sendBadRequest("error validating field $field with value $value")
And the errorsender has a sendBadRequest method
[response: ['message': message, error: "bad_request", status: 400, cause: []], status: 400]
If the request was OK, you only need to respond the data with something like
return [response: results, status: 200]
In the client side you have to have one function if the request was OK to parse result, and one function if request have some validated data problem, database problem or whatever that caused that the request didnĀ“t return a 200(in the example),there are more status codes, you can check on
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
PD: Initial validation should be done on client side.

No MediaTypeFormatter error when trying to parse ReadAsFormDataAsync result in WebAPI

I have created a WebAPI project to help capture statements from a TinCan learning course but I am having extreme difficulty in retrieving any of the Request payload details. Within this payload I pass the whole statement that I am trying to capture but upon trying to read using:
var test = Request.Content.ReadAsFormDataAsync().Result.ToString();
I get the following error message:
No MediaTypeFormatter is available to read an object of type 'FormDataCollection' from content with media type 'application/json'.
I have tried Converting the result object to JSON to overcome this problem but it has not been any use. Do I need to configure json somewhere in the configuration? I have tried adding
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
and also:
var jsonFormatter = config.Formatters.JsonFormatter;
config.Formatters.Insert(0, jsonFormatter);
to my WebApiConfig.cs file as answered in another question of how to return json but I cannot seem to pass this error. I have also set config.formatter to accept application/json but this also has not worked
CONTROLLER CODE
public void Put([FromBody]string statementId)
{
var test = Request.Content.ReadAsFormDataAsync().Result;
System.Diagnostics.EventLog.WriteEntry("Application", "/xAPI/PUT has been called", System.Diagnostics.EventLogEntryType.Error);
}
From the error message you have provided, it seems like request content is in application/json. ReadAsFormDataAsync() can only read content of type application/x-www-form-urlencoded.
In this case, you can use ReadAsAsync<> if you have the type you want to be deserialized defined or simply use ReadAsStringAsync<> if you just want to read the content as a string.