Grails send request as JSON and parse it in controller - json

I want to send a request as JSON and in my controller I want to parse this JSON and get the parameters I want. for example this is the request:
{"param1":"val1"}
I want to parse this request and get "param1" value. I used request.JSON but still I got null. Is there any other way to solve this?
Thanks,

You can use one of the following to test your stuff (both options could be re-used as automated tests eventually - unit and integration):
write a unit test for you controller like (no need to start the server):
void testConsume() {
request.json = '{param1: "val1"}'
controller.consume()
assert response.text == "val1"
}
and let's say your controller.consume() does something like:
def consume() {
render request.JSON.param1
}
Or you can use for example the Jersey Client to do a call against your controller, deployed this time:
public void testRequest() {
// init the client
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
// create a resource
WebResource service = client.resource(UriBuilder.fromUri("your request url").build());
// set content type and do a POST, which will accept a text/plain response as well
service.type(MediaType.APPLICATION_JSON).accept(MediaType.TEXT_PLAIN).put(Foo.class, foo);
}
, where foo is a Foo like this:
#XmlRootElement
public class Foo {
#XmlElement(name = "param1")
String param1;
public Foo(String val){param1 = val;}
}
Here are some more examples on how to use the Jersey client for various REST requests:
https://github.com/tavibolog/TodaySoftMag/blob/master/src/test/java/com/todaysoftmag/examples/rest/BookServiceTest.java

Set it in your UrlMappings like this:
static mappings = {
"/rest/myAction" (controller: "myController", action: "myAction", parseRequest: true)
}
Search for parseRequest in latest Grails guide.
Then validate if it works correctly with curl:
curl --data '{"param1":"value1"}' --header "Content-Type: application/json" http://yourhost:8080/rest/myAction

In the controller method, check request.format. It should specify json. I'm guessing it won't here, but it may give you clues as to how your payload is being interpreted.
In your Config.groovy file, I would set the following values:
grails.mime.file.extensions = false
grails.mime.use.accept.header = false
In that same file, check your grails.mime.types. make sure it includes json: ['application/json', 'text/json'], which it probably will, but put it above */*. These entries are evaluated in order (this was true in pre 2.1 versions, havent' verified it is now, but what the heck). In conjunction with that, as aiolos mentioned, set your content-type header to one of the above mime-types.
Finally, test with curl, per Tomasz Kalkosiński, or, to use RESTClient for FF, click on "Headers" in the very top of the client page (there are 4 clickable items at the top-left; headers is one. From a fresh RESTClient, you may have to choose "Custom Header". I can't recall)

Related

test springboot restcontroller consume json and optional file using postman

i have a rest endpoint in my controller like this..
#RequestMapping(value = "/createFoo", method = RequestMethod.POST)
public ResponseEntity<Void> createFoo(#RequestPart(name = "foo") Foo foo,
#RequestPart(name = "file", required = false) MultipartFile file) {
service.createFoo(foo, file);
return new ResponseEntity<>(HttpStatus.CREATED);
}
how can i test this out using postman and curl? i need to send a json foo with or without a file. thanks in advance.
you can shorten it like this #PostMapping("/createFoo")
Firstly specify your method Post and url that postman requested it than
select form-data under Body section
Click key input area and change text to File
In addition parameter name need to be same as form-data variable
Example attached

Grails 2.5.0 controller command object binding after accessing request.JSON in a filter

In a Grails 2.5.0 controller action method, it seems like the properties in the HTTP JSON body will not be used for command object binding if request.JSON has been accessed in a filter.
Why is that? It doesn't make any sense to me.
Is there any way to allow request.JSON to be used in a filter, and also for command object binding?
Yes, this is the default behavior of Grails while it comes to data binding with request body. When you read the request body via request.JSON in your filter then the corresponding input stream will be closed or gets empty. So, now Grails can't further access that request body to bind to the command object.
So, you can either access the request body on your own in the filter or can use it with the command object but can't both.
From Binding The Request Body To Command Objects heading http://grails.github.io/grails-doc/2.5.0/guide/theWebLayer.html#dataBinding:
Note that the body of the request is being parsed to make that work.
Any attempt to read the body of the request after that will fail since
the corresponding input stream will be empty. The controller action
can either use a command object or it can parse the body of the
request on its own (either directly, or by referring to something like
request.JSON), but cannot do both.
So, what are you trying to achieve is not possible directly. But, you can do something different. In your filter, read the incoming request body and store into the params or session (if filter passes the request to controller) and then manually bind the parameter in action:
MyFilters.groovy
class MyFilters {
def filters = {
foo(/* your filter */) {
before = {
// Your checks
Map requestData = request.JSON as Map
session.requestData = requestData
return true
}
}
}
}
Now, in your controller action, instead of doing:
class MyController {
def fooAction(MyCommandObject object) {
}
}
Do something like this:
class MyController {
def fooAction() {
MyCommandObject object = new MyCommandObject(session.requestData)
// Clear from session to clear up the memory
session.requestData = null
}
}
Update: The above solution, I've provided will work well but is not clean. #JoshuaMoore provided a link with a cleaner solution Http Servlet request lose params from POST body after read it once.

Setting Http Status Code and customized status message and returning JSON output using Jersey in RESTful Service

I have implemented a RESTful service using Jersey. I am able to return the desired output in JSON format. But, I also need to set Http Status Code and my customized status message. Status code and status message should not be part of the JSON output.
I tried following links:
JAX/Jersey Custom error code in Response
JAX-RS — How to return JSON and HTTP status code together?
Custom HTTP status response with JAX-RS (Jersey) and #RolesAllowed
but I am able to perform only one of the tasks, either returning JSON or setting HTTP status code and message.
I have code something like below:
import javax.ws.rs.core.Response;
public class MyClass(){
#GET
#Produces( { MediaType.APPLICATION_JSON })
public MyObject retrieveUserDetails()
{
MyObject obj = new MyObject();
//Code for retrieving user details.
obj.add(userDetails);
Response.status(Status.NO_CONTENT).entity("The User does not exist").build();
return obj;
}
}
Can anyone provide solution to this?
the mistakes are :
1. if status is set to NO_content (HTTP204) the norm is to have an entity empty. so entity will be returned as empty to your client. This is not what you want to do in all case, if found return details, if not found return 404.
2.Produces( { MediaType.APPLICATION_JSON }) tells that you will return a json content, and the content of entity is not a json. You will have to return a json. You will see I use jackson as it's part of Jersey.
set a #Path("/user") to set a endpoint path at least at Resource level.
Need to set a path in order to adress your resource (endpoint)
use a bean in order to pass multiple things. I've made an example bean for you.
as improvement caution with HTTP return, use the proper one
404 :not found resource
204 : empty....
take a look at the norm: http://www.wikiwand.com/en/List_of_HTTP_status_codes
Take a look the complete code in Gist: https://gist.github.com/jeorfevre/260067c5b265f65f93b3
Enjoy :)

MediaType should be application/schema+json to validate schema

I'm using justinrainbow/json-schema class to validate data against a schema.
However I'm receiving this error:
Media type application/schema+json expected
I could try to change ContentType in nginx for all my json files, but it doesn't make sense.
Another way would be to change the constant inside the library to 'application/json' (as my server is delivering for json files). Again, is not ok to change the source.
Is there a way to pass this as a parameter to justinrainbow/json-schema class?
https://github.com/justinrainbow/json-schema
I couldn't find a solution for this because there is no content-type on the web as schema+json.
Just replace in justinrainbow/json-schema/src/JsonSchema/Validator.php the SCHEMA_MEDIA_TYPE to 'application/json'.
You can also serve the file by local path, not by url.
Now the library supports "json/application" additionally, but it throws an error at other content types.
To avoid this, you can extend the default "JsonSchema\Uri\UriRetriever" and override "confirmMediaType()":
class MyUriRetriever extends JsonSchema\Uri\UriRetriever {
public function confirmMediaType($uriRetriever, $uri) {
return;
}
}
$retriever = new \MyUriRetriever();
$refResolver = new JsonSchema\SchemaStorage($retriever);
$schema = $refResolver->resolveRef($schema);
$validator = new JsonSchema\Validator(new JsonSchema\Constraints\Factory($refResolver));
$validator->check($data, $schema);
$data: json decoded response from API
$schema: url of the schema
I had the same issue many times when testing other party`s API against their schema. Often they do not send the correct "Content-Type" header for their schemas and it can take long for them to change it.
Update: Ability to exclude endpoints from validation
You can use UriRetriever:addInvalidContentTypeEndpoint():
$retriever = new UriRetriever();
$retriever->addInvalidContentTypeEndpoint('http://example.com/car/list');

NoJson found on an http request on play 2.3.2

i'm writing a Play 2.3.2 application using Scala.
In my controller i had a method which get the json object from the request.
The implementation is like the following:
def firstTags = Action.async { request =>
def elaborate(n: Int): Future[Result] = {//some implementation}
//get the json Object
val jsonObject = request.body.asJson
//parse the json object
jsonObject match {
case Some(json) => json \ "number" match {
case x: JsNumber => elaborate(x.as[Int])
case _ => Future{BadRequest}
}
case None => Future{BadRequest("Need a Json")}
}
}
In my route files i had:
GET /recommendation/statistic/first #recommendationsystem.controllers.manager.StatisticsController.firstTags
When i try to call the method with the curl i get always a "Need a Json" response.
I call my server with curl like the following:
curl -H "Accept: application/json" -H "Content-Type: application/json" -d '{"number": 3}' -X GET http://localhost:9000/recommendation/statistic/first
What's wrong??
GET shouldn't have body. look at HTTP GET with request body.
POST method is not only for modify the server state, but also to process data.
From RFC 2616 - HTTP/1.1:
The POST method is used to request that the origin server accept the
entity enclosed in the request as a new subordinate of the resource
identified by the Request-URI in the Request-Line. POST is designed
to allow a uniform method to cover the following functions:
Annotation of existing resources;
Posting a message to a bulletin board, newsgroup, mailing list,
or similar group of articles;
Providing a block of data, such as the result of submitting a
form, to a data-handling process;
Extending a database through an append operation.
The actual function performed by the POST method is determined by the
server and is usually dependent on the Request-URI. [...]