I have an incoming JSON request like:
{ 'foo': 'bar' }
I want to modify this message and then forward it along to SNS, which requires mapping the incoming JSON body to outgoing URL parameters.
Currently, I have a template akin to the following:
#set($modified = {
'additionalProperty': 'bar',
'originalMessage': $input.path('$')
})
#set($context.requestOverride.querystring.Message = $util. base64Encode('$'))
When logged, $modified is represented accurately as:
{
'additionalProperty': 'bar',
'originalMessage': { 'foo': 'bar' }
}
But will always render as:
{
'additionalProperty' = 'bar',
'originalMessage' = { 'foo' = 'bar' }
}
This seems to happen regardless of the method used to render the modified structure as a header.
Both of the following will result in the above key = value format once decoded: $util.base64Encode(), $util.urlEncode()
How do I force API Gateway to convert a JSON body into a mapping template header while preserving the original JSON format?
Related
I am trying to attach a file in EWS using Node JS but I keep getting the error:
The request failed schema validation: Name cannot begin with the '0' character, hexadecimal value 0x30
I've read online that it could be related to some spaces in the XML namespace (since EWS uses SOAP) but as you can see, in the following method below, I am using JSON format (which is translated by node-ews module into XML at a lower level) so I doubt it's a malformed request unless there is a bug in node-ews (because other requests work just fine - it's just the file attachment that's failing)! Any help would be appreciated.
function createAttachment(id, changeKey, fileName, content) {
var ewsFunction = 'CreateAttachment';
var ewsArgs = {
'ParentItemId': {
'attributes': {
'Id': id,
'ChangeKey': changeKey
}
},
'Attachments': {
'FileAttachment': {
'Name': fileName,
'Content': content
}
}
}
return ews.run(ewsFunction, ewsArgs)
.then(result => {
return result.ResponseMessages.CreateAttachmentResponseMessage.Attachments.FileAttachment.AttachmentId;
})
.catch(err => console.log(err.message));
}
Hisham
POST ing json from javascript to server in Play Framework:
var myJson = {"name": "joe", "age":20};
var obj = JSON.parse(myJson);
$.ajax(jsRoutes.controllers.MyController.create(obj));
Now, I have the javascript router configured fine. If i recieve the obj as a string I can print it out to the console just fine.
routes.conf:
POST /person/add controllers.MyController.createFromAjax(ajax: String)
BUT, I want to write the json to MongoDB using an Async promise which Activator gives the compile time error:
scala.concurrent.Future[play.api.mvc.Result][error] cannot be applied to (String)
I have other routes that take no parameters that receive json using Postman and write it to MongoDB just fine
routes.conf
POST /heartrates/bulk controllers.HRController.createFromJson
If I omit the parameter on the route that receives the json from Ajax instead of using Postman I get a HTTP 400 error in the browser.
POST http://localhost:9000/person/add 400 (Bad Request)
SO, my question is, Ajax needs a parameter but String wont work. Play documentation says json is always received as a String. What am I doing wrong here?
Scala Controller Code taken from Lightbend seed Play.Reactive.MongoDB:
def createBulkFromAjax = Action.async(parse.json) { request =>
val documents = for {
heartRate <- request.body.asOpt[JsArray].toStream
maybeHeartRate <- heartRate.value
validHeartRate <- maybeHeartRate.transform(transformer).asOpt.toList
} yield validHeartRate
for {
heartRate <- hrFuture
multiResult <- heartRate.bulkInsert(documents = documents, ordered = true)
} yield {
Logger.debug(s"Successfully inserted with multiResult: $multiResult")
Created(s"Created ${multiResult.n} heartRate")
}
}
I think you're getting mixed up between the parameters you pass to your Action as part of the jsRoutes call, and parameters that get passed to endpoints (i.e. the query string, query parameters etc).
Play will return a 400 Bad Request if you've declared a non-optional parameter (like you did with ajax: String) and you don't then actually supply it in your request.
While conceptually you are passing obj to your action, it's not as a query parameter - you've declared that your endpoint expects an HTTP POST - so the JSON should be in the HTTP request body. Notice your other endpoints don't take any query parameters.
So step 1 is to fix your routes file (I've renamed your method to match your other existing working one):
POST /person/add controllers.MyController.createFromJson
If you look at the Play documentation for the Javascript reverse router, you'll see that you'll need to set the type (aka HTTP method) if you're doing something other than a GET. So, step 2, here's what your Javascript should look like to achieve a POST:
var myJson = {"name": "joe", "age":20};
var obj = JSON.stringify(myJson);
var r = controllers.MyController.createFromJson;
$.ajax({url: r.url, type: r.type, data: obj });
After those changes you should be good; your controller code looks fine. If you still get 400 Bad Request responses, check that jQuery is setting your Content-Type header correctly - you may need to use the contentType option in the jQuery $.ajax call.
Edit after still getting 400 errors:
I've just noticed that you were using JSON.parse in your Javascript - as per this answer you should be using JSON.stringify to convert an object into something jQuery can send - otherwise it may try to URLEncode the data and/or send the fields as query parameters.
The other thing to look at is whether the JSON you are sending actually agrees with what you're trying to parse it as. I'm not sure if you've provided a simplified version for this question but it looks like you're trying to parse:
{"name": "joe", "age":20}
Using:
request.body.asOpt[JsArray]
Which will always result in a None - you didn't give it an array.
The Answer to ajax javascript routes in Play Framework 2.5 for ReativeMongo:
routes.conf:
GET /javascriptRoutes controllers.HRController.javascriptRoutes
HRController:
def javascriptRoutes = Action { implicit request =>
Ok(
JavaScriptReverseRouter("jsRoutes")(
routes.javascript.HRController.createBulkFromAjax
)
).as("text/javascript")
}
routes.conf:
POST /heartrates/add controllers.HRController.createBulkFromAjax
main.scala.html:
<script type="text/javascript" src="#routes.HRController.javascriptRoutes"></script>
javascript:
var r = jsRoutes.controllers.HRController.createBulkFromAjax();
$.ajax({url: r.url, type: r.type, contentType: "application/json", data: JsonString });
HRController:
def createBulkFromAjax = Action.async(parse.json) { request =>
//Transformation silent in case of failures.
val documents = for {
heartRate <- request.body.asOpt[JsArray].toStream
maybeHeartRate <- heartRate.value
validHeartRate <- maybeHeartRate.transform(transformer).asOpt.toList
} yield validHeartRate
for {
heartRate <- hrFuture
multiResult <- heartRate.bulkInsert(documents = documents, ordered = true)
} yield {
Logger.debug(s"Successfully inserted with multiResult: $multiResult")
Created(s"Created ${multiResult.n} heartRate")
}
}
HRController.createBulkFromAjax was built from a Lightbend activator ui seed example called play.ReactiveMogno
In after inline edit free jqgrid sends variable number of columns to ASP.NET MVC4 WebAPI controller using POST method.
Posted data contains json string below.
json string posted to controller in POST body looks like:
{"Toode":"","Kogus":"0.0000",
"Nimetus":"1","Mootyhik0_nimetus":"",
"Reanr":"2",
"_oper":"edit","_rowid":"1673",
"_dokdata":"[
{\"name\":\"Maksetin1_tingimus\",\"value\":\"\"},
{\"name\":\"Kinnitatud\",\"value\":\"False\"}]"
}
It has 3 regions of properties:
Order details. Dynamic properties "Toode":"","Kogus":"0.0000","Nimetus":"1","Mootyhik0_nimetus":"",
"Reanr":"2"
This list may change on runtime depending on user preferences.
This is created by using jqgrid extraparam: getDetails() setting.
Fixed properties stating with underscore `"_oper":"edit","_rowid":"
Those are
_oper and _rowid are always present
jqgrid adds them automatically.
Order data. fixed property _dokdata which contains json array of dynamic properites {\"name\":\"Maksetin1_tingimus\",\"value\":\"\"},{\"name\":\"Kinnitatud\",\"value\":\"False\"}
This is created from jqgrid colmodel.
This list may change in runtime and may contain same poperty names as in p.1 order details.
How to get this data in controller ? Probably it shoud be parsed into two dictionaries . Is it possible to force WebAPI to pass this data as classes/collection to controller or should it parsed manually?
jqgrid settings are from answer Using jqGrid's inline-editing with RESTful urls?
Those and serialize methods can changed if this makes data passing more reasonable.
Resulting WebAPI should have easily understandable data format (good API) since it will be used by third party applications also.
$.extend($.jgrid.defaults, {
ajaxRowOptions: { contentType: "application/json", async: true },
serializeRowData: function (data) {
var propertyName, propertyValue, dataToSend = {};
for (propertyName in data) {
if (data.hasOwnProperty(propertyName)) {
propertyValue = data[propertyName];
if ($.isFunction(propertyValue)) {
dataToSend[propertyName] = propertyValue();
} else {
dataToSend[propertyName] = propertyValue;
}
}
}
return JSON.stringify(dataToSend);
}
});
Update
serializeRowData is changed to
serializeRowData: function (data) {
return JSON.stringify({
headerData: $("#_form").serializeArray(),
rowData: data
} );
}
This produces bloated json for headerData:
{"headerData": [
{"name":"Tasudok","value":"134"},
{"name":"Kuupaev","value":"2015-11-23"},
{"name":"Dokumnr","value":"135319"}
],
"rowData": {"Toode":"",
"Kogus":"0.0000",
"Nimetus":"öäölä<a",
"_rowsum":"0.00",
"Id":"1639",
"Dokumnr":"135319",
"_oper":"edit",
"_rowid":"1639"
}
}
How remove name and value properties from headerData so that it contains property name and value pairs like in rowData:
headerData: {
"Tasudok": "134",
"Kuupaev": "2015-11-23",
"Dokumnr": "135319"
}
I am trying to render a json response from grails controller action. Here is my code:
render ([message:"voila Sent Successfully!"]) as JSON
But in the gsp, it is rendering like:
['message':'Email Sent Successfully!']
Above text is actually a string(as its typeof in jquery ajax call gives a string in the success event handler), so how do I render it as a JSON?
I am using grails 2.4.5 and the JSON class is actually grails.converters.JSON (not grails.converters.deep.JSON)
Just do as
render ([message:"voila Sent Successfully!"] as JSON ) i.e inserting as JSON
within parentheses.
I'd like to expose another answer, which avoids an issue like one that I already found in IE. Some older IE versions could try to download your JSON as a file.
Generate your JSON response from your collection/map and then render it as a string, so:
import grails.converters.JSON
def YourService
def yourControllerNameHere(){
def result = YourService.generatesYourResult(),
resultJSON = result as JSON
render resultJSON.toString()
}
Then, in your ajax, parse this string as JSON-object using jQuery, that is:
$.ajax({
url : WEB_ROOT + 'yourUrl/yourControllerNameHere',
type : 'post',
dataType: 'text',
success : function(resultStr) {
var result = $.parseJSON(resultStr);
alert('this is your response type: ' + (typeof result));
// this is your response type: object
}
});
I would like to use some expression language in JSON objects. Let's say I have a "template" like:
jsonTemplate = {
title:"Title: '#{title}',
header: "Created by #{meta.author} at #{meta.createdAt}"
}
and the actual data as follows:
data = {
title: "Some title",
content:"bla...",
meta: {createdAt:new Date(), author:"me"}
}
I would like to do something similar to
parser.render(jsonTemplate, data);
to return
{
title:"Title: 'Some title'",
header: "Created by me at 2012-05-10 10:00:00"
}
All the template engines focus on html generation, but the result of the "render" step should be a json object.
Is there any engine which allows this?
If not, I would create the json object myself and apply an existing engine to the single attributes. Would you recommend an engine for this?
Ideally this should be available as node.js module or common.js.