Handling and serving JSON requests

Handling a JSON request

A JSON request is an HTTP request using a valid JSON payload as request body. Its Content-Type header must specify the text/json or application/json MIME type.

An action can retrieve the raw body content, or can ask Wisdom to convert it to an object, such as a JSON Node object in the following example:

include::{sourcedir}/controllers/json/JsonController.java[tags=hello-json]

Of course, it’s much better to use the @Body annotation:

include::{sourcedir}/controllers/json/JsonController.java[tags=hello-json-with-body]

In this example, the body is automatically mapped to a JsonNode. The @NotNull annotation manages the case where the body is empty. A bad request result will be sent back.

A third, even better, way to receive Json content is to use a validated bean/structure instead of a JsonNode:

include::{sourcedir}/controllers/json/JsonController.java[tags=hello-json-with-body-and-bean]

The structure contains validation annotation, constraining the received data. For any non compliant content, a bad request will be returned. In addition, this way also accepts requests with other types of content (such as form input).

Serving a JSON response

In our previous examples we handled requests with a JSON body, but replied with a text/plain response. Let’s change that to send back a valid JSON HTTP response:

include::{sourcedir}/controllers/json/JsonController.java[tags=build-json-using-json-service]
  1. First, access the Wisdom Json service using the @Requires annotation.

  2. Create a new (Jackson) ObjectNode from the retrieves Json service

  3. Just pass the created object in the ok method

Invoked with the {"name":"wisdom"} payload, the action returns:

{
  "name" : "wisdom",
  "message" : "hello wisdom"
}

However, building your own Json object can be very annoying and cumbersome. Fortunately, Wisdom builds a Json representation from an object:

include::{sourcedir}/controllers/json/JsonController.java[tags=build-json-using-mapping]
  1. Define the structure you want to return

  2. Pass the created object to the ok method and invoke the json method

Extending Json support with your own serializer and deserializer

Wisdom relies on Jackson to handle the JSON requests and responses. Despite the provided defaults serialization and de-serialization processes, you may need to extend it with your own mapping. Wisdom lets you extend Jackson by registering Jackson’s modules containing serializers and deserializers.

Your custom serializers and deserializers must be registered within a module and then registered to the JacksonModuleRepository service (provided by Wisdom itself):

include::{sourcedir}/controllers/json/MyJsonModuleProvider.java[tags=controller]
  1. Retrieve the MyJsonModuleProvider service

  2. In your constructor, build your module with a set of serializers and deserializers.

  3. Registers your module into the repository

  4. Don’t forget to unregister the module from the repository

JSONP

JSON with Padding (JSONP) is a communication technique to request data from a server in a different domain, something prohibited by typical web browsers because of the same-origin policy. To use JSONP, the server must be able to generate a JSONP response, and you know what ? Wisdom knows how to do that.

Basically a JSONP response is a JavaScript code fragment structure as follows: padding({the data});. The padding is the name of the method (callback) that will be called in the JavaScript code having requested this response.

There are several ways to generate a JSONP response:

  • using the ok(padding, json node) method

  • using the Json Service

include::{sourcedir}/controllers/jsonp/JsonPController.java[tags=renderable]

The previous snippet uses the first way to get a JSONP response. It builds a JSON Node and creates a JSONP result object. The mime type of the response is set to text/javascript. The previous code generates callback({"foo":"bar"});.

JSONP responses can be generated from the JSON service too:

include::{sourcedir}/controllers/jsonp/JsonPController.java[tags=json]

The json.toJSONP method generates the JSONP response from the given callback name (padding) and the given content. This approach is convenient as you can map business objects into JSON directly (as shown in the second example). However it requires setting the JavaScript mime type explicitly.