Grails "params" doesn't contain json payload for REST controllers - json

I'm writing REST API for my app.
Using JSON payload in the POST request:
{
availableAfter: "2014-03-16"
canRead: true
rightName: "dsa"
}
The problem is that, in the controller's params there are no values from payload.
But, despite that, I can read them using properties[*] syntax, like this:
right.properties['rightName', 'canRead'] = params;
right.availableAfter = params.date('availableAfter', 'yyyy-MM-dd');
Properties 'rightName' and 'canRead' are set OK. 'availableAfter' is not(null even if taken with params.availableAfter).
Why is it differs?
UPDATE: Grails v 2.3.6

You have to use request.JSON to get a hold of your JSON-body.
The params object doesn't contain it, unless you serialize your JSON object in the client and pass it as a parameter.

Related

Why doesn't the json model's odata property have columns?

I am creating a JSON model in UI5 from a json object. But it is missing the columns array in the JSON model. I checked the model in the console and the odata property had no columns. Check image for proof.
https://ibb.co/hLmYpZb
Hence I want to know how I can get the column to show up.
Here is my code.
var emptyModel = {
"columns": []
};
this.setModel(new JSONModel(JSON.stringify(emptyModel)), "selcontent");
I expect column to show up in the JSON model under the odata property.
JSONModel awaits a plain object or a URL string as the first argument.
Either the URL where to load the JSON from or a JS object (source)
The result of the stringified emptyModel is "{"columns":[]}" which is neither an object nor a URL.

Camel binding mode for JSON not working, cant unmarshal it to POJO

I'm trying to send message from rest API to new route, and even thou I receive request in JSON format on my REST API and binding is set to JSON, when I forward it to new route it will be shown as InputStream and I will have to marshal it to JSON in order to use it.
I already tried using streamCaching and other components in RestConfiguration (consumes, produces, type, dataType). Also i'm using all dependencies in POM.
public void configure() {
restConfiguration().component("servlet")
.bindingMode(RestBindingMode.json)
.skipBindingOnErrorCode(false);
rest("/resttest")
.patch("/t1")
.id("t1")
.description("t1")
.consumes("application/json")
.produces("application/json")
.param()
.name("body")
.type(RestParamType.body)
.dataType("json")
.required(true)
.endParam()
.to("direct:test2");
This route is in other class:
from("direct:test2").id("test2")
.marshal().json(JsonLibrary.Jackson,SomePOJO.class)
.unmarshal().json(JsonLibrary.Jackson, SomePOJO.class)
.choice()
.when(simple("${body.getStatus()} =~ 'Closed'"))
.....
I was expecting to get JSON message on test2 route, and somehow I get InputStream, so i have to do marshaling first. Anybody know how I can make REST API forward me to route message in JSON format, not as stream?
Try:
.convertBodyTo(String.class)
before your unmarshal.
I was having the same issue, and I had to apply the marshal method for incoming values and unmarshal method for response.
This was the response in postman:
And I was using this code:
rest(service.service)
.description(ContentCategory.api("Service Test"))
.post("/product/{productType}/{enterpriseId}")
.description("service for saving a product")
.consumes(MediaType.APPLICATION_JSON)
.type(Product.class)
.bindingMode(RestBindingMode.json)
.produces(MediaType.APPLICATION_JSON)
.outType(String.class)
.route()
.bean("productService", "saveProduct")
.marshal()
.json(JsonLibrary.Jackson)
.setHeader(Exchange.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON))
.endRest();
I just added the unmarshall method after realizing that I was receiving an InputStream
rest(service.service)
.description(ContentCategory.api("Service Test"))
.post("/product/{productType}/{enterpriseId}")
.description("service for saving a product")
.consumes(MediaType.APPLICATION_JSON)
.type(Product.class)
.bindingMode(RestBindingMode.json)
.produces(MediaType.APPLICATION_JSON)
.outType(String.class)
.route()
.bean("productService", "saveProduct")
.marshal()
.json(JsonLibrary.Jackson)
.unmarshal()
.json(JsonLibrary.Jackson)
.setHeader(Exchange.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON))
.endRest();
In fact, I just added this two lines
.unmarshal()
.json(JsonLibrary.Jackson)
And it starts working:
It think is probably you need to use the unmarshal method for the resttest service.

Bad Request response when passing a JSON in process variables - flowable

I'm using flowable and try to pass a JSON as body, but it's seen as malformed when processing the request (or so I think since the error is Bad Request). Basically I'm passing some parameters this way:
#PostMapping(path = PathConstants.START_ACTION)
public ResponseEntity<BaseResponse<ProcessInstance>> start(#PathVariable String processDefinitionId,
#RequestBody(required = false) Map<String, Object> params)
The params are set using postman, this way:
{
"body": {
"email":"testmail#test",
"password":"password"
}
}
The process starts and the POST call is made, but Bad Request is given back. I've tried printing the variables of the process after this call and this is what I have:
body={email=testmail#test, password=password}
So I've tried passing this instead:
{
"body": "{ \"email\":\"testmail#test\", \"password\":\"password\"}"
}
And when printing the variables I have:
body={"email":"testmail#test", "password":"password"}
but still it's a bad request. What is wrong with this JSON?
If you want to pass a variable that is a JSON then you would need to make sure that body is type JsonNode from Jackson.
Looking at your request signature Map<String, Object>, Jackson would contain a map of maps.
I don't know what you are trying to do. However, I would highly advise you to work with predefined parameters in your REST API. If you need something generic you can use the REST API of Flowable to do what you want to do.

How can I define a ReST endpoint that allows json input and maps it to a JsonSlurper

I want to write an API ReST endpoint, using Spring 4.0 and Groovy, such that the #RequestBody parameter can be any generic JSON input, and it will be mapped to a Groovy JsonSlurper so that I can simply access the data via the slurper.
The benefit here being that I can send various JSON documents to my endpoint without having to define a DTO object for every format that I might send.
Currently my method looks like this (and works):
#RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<String> putTest(#RequestBody ExampleDTO dto) {
def json = new groovy.json.JsonBuilder()
json(
id: dto.id,
name: dto.name
);
return new ResponseEntity(json.content, HttpStatus.OK);
}
But what I want, is to get rid of the "ExampleDTO" object, and just have any JSON that is passed in get mapped straight into a JsonSlurper, or something that I can input into a JsonSlurper, so that I can access the fields of the input object like so:
def json = new JsonSlurper().parseText(input);
String exampleName = json.name;
I initially thought I could just accept a String instead of ExampleDTO, and then slurp the String, but then I have been running into a plethora of issues in my AngularJS client, trying to send my JSON objects as strings to the API endpoint. I'm met with an annoying need to escape all of the double quotes and surround the entire JSON string with double quotes. Then I run into issues if any of my data has quotes or various special characters in it. It just doesn't seem like a clean or reliable solution.
I open to anything that will cleanly translate my AngularJS JSON objects into valid Strings, or anything I can do in the ReST method that will allow JSON input without mapping it to a specific object.
Thanks in advance!
Tonya

Standardized way to serialize JSON to query string?

I'm trying to build a restful API and I'm struggling on how to serialize JSON data to a HTTP query string.
There are a number of mandatory and optional arguments that need to be passed in the request, e.g (represented as a JSON object below):
{
"-columns" : [
"name",
"column"
],
"-where" : {
"-or" : {
"customer_id" : 1,
"services" : "schedule"
}
},
"-limit" : 5,
"return" : "table"
}
I need to support a various number of different clients so I'm looking for a standardized way to convert this json object to a query string. Is there one, and how does it look?
Another alternative is to allow users to just pass along the json object in a message body, but I read that I should avoid it (HTTP GET with request body).
Any thoughts?
Edit for clarification:
Listing how some different languages encodes the given json object above:
jQuery using $.param: -columns[]=name&-columns[]=column&-where[-or][customer_id]=1&-where[-or][services]=schedule&-limit=5&return=column
PHP using http_build_query: -columns[0]=name&-columns[1]=column&-where[-or][customer_id]=1&-where[-or][services]=schedule&-limit=5&return=column
Perl using URI::query_form: -columns=name&-columns=column&-where=HASH(0x59d6eb8)&-limit=5&return=column
Perl using complex_to_query: -columns:0=name&-columns:1=column&-limit=5&-where.-or.customer_id=1&-where.-or.services=schedule&return=column
jQuery and PHP is very similar. Perl using complex_to_query is also pretty similar to them. But none look exactly the same.
URL-encode (https://en.wikipedia.org/wiki/Percent-encoding) your JSON text and put it into a single query string parameter. for example, if you want to pass {"val": 1}:
mysite.com/path?json=%7B%22val%22%3A%201%7D
Note that if your JSON gets too long then you will run into a URL length limitation problem. In which case I would use POST with a body (yes, I know, sending a POST when you want to fetch something is not "pure" and does not fit well into the REST paradigm, but neither is your domain specific JSON-based query language).
There is no single standard for JSON to query string serialization, so I made a comparison of some JSON serializers and the results are as follows:
JSON: {"_id":"5973782bdb9a930533b05cb2","isActive":true,"balance":"$1,446.35","age":32,"name":"Logan Keller","email":"logankeller#artiq.com","phone":"+1 (952) 533-2258","friends":[{"id":0,"name":"Colon Salazar"},{"id":1,"name":"French Mcneil"},{"id":2,"name":"Carol Martin"}],"favoriteFruit":"banana"}
Rison: (_id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller#artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258')
O-Rison: _id:'5973782bdb9a930533b05cb2',age:32,balance:'$1,446.35',email:'logankeller#artiq.com',favoriteFruit:banana,friends:!((id:0,name:'Colon Salazar'),(id:1,name:'French Mcneil'),(id:2,name:'Carol Martin')),isActive:!t,name:'Logan Keller',phone:'+1 (952) 533-2258'
JSURL: ~(_id~'5973782bdb9a930533b05cb2~isActive~true~balance~'!1*2c446.35~age~32~name~'Logan*20Keller~email~'logankeller*40artiq.com~phone~'*2b1*20*28952*29*20533-2258~friends~(~(id~0~name~'Colon*20Salazar)~(id~1~name~'French*20Mcneil)~(id~2~name~'Carol*20Martin))~favoriteFruit~'banana)
QS: _id=5973782bdb9a930533b05cb2&isActive=true&balance=$1,446.35&age=32&name=Logan Keller&email=logankeller#artiq.com&phone=+1 (952) 533-2258&friends[0][id]=0&friends[0][name]=Colon Salazar&friends[1][id]=1&friends[1][name]=French Mcneil&friends[2][id]=2&friends[2][name]=Carol Martin&favoriteFruit=banana
URLON: $_id=5973782bdb9a930533b05cb2&isActive:true&balance=$1,446.35&age:32&name=Logan%20Keller&email=logankeller#artiq.com&phone=+1%20(952)%20533-2258&friends#$id:0&name=Colon%20Salazar;&$id:1&name=French%20Mcneil;&$id:2&name=Carol%20Martin;;&favoriteFruit=banana
QS-JSON: isActive=true&balance=%241%2C446.35&age=32&name=Logan+Keller&email=logankeller%40artiq.com&phone=%2B1+(952)+533-2258&friends(0).id=0&friends(0).name=Colon+Salazar&friends(1).id=1&friends(1).name=French+Mcneil&friends(2).id=2&friends(2).name=Carol+Martin&favoriteFruit=banana
The shortest among them is URL Object Notation.
How about you try this sending them as follows:
http://example.com/api/wtf?
[-columns][]=name&
[-columns][]=column&
[-where][-or][customer_id]=1&
[-where][-or][services]=schedule&
[-limit]=5&
[return]=table&
I tried with a REST Client
And on the server side (Ruby with Sinatra) I checked the params, it gives me exactly what you want. :-)
Another option might be node-querystring. It also uses a similar scheme to the ones you've so far listed.
It's available in both npm and bower, which is why I have been using it.
Works well for nested objects.
Passing complex objects as query parameters of a url.
In the example below, obj is the JSON object to pass into query parameters.
Injecting JSON object as query parameters:
value = JSON.stringify(obj);
URLSearchParams to convert a string to an object representing search params. toString to retain string type for appending to url:
queryParams = new URLSearchParams(value).toString();
Pass the query parameters using template literals:
url = `https://some-url.com?key=${queryParams}`;
Now url will contain the JSON object as query parameters under key (user-defined name)
Extracing JSON from url:
This is assuming you have access to the url (either as string or URL object)
url_obj = new URL(url); (only if url is NOT a URL object, otherwise ignore this step)
Extract all query parameters in the url:
queryParams = new URLSearchParams(url_obj.search);
Use the key to extract the specific value:
obj = JSON.parse(queryParams.get('key').slice(0, -1));
slice() is used to extract a tailing = in the query params which is not required.
Here obj will be the same object passed in the query params.
I recommend to try these steps in the web console to understand better.
You can test with JSON examples here: https://json.org/example.html