A TEXT POST

GWT applications as REST clients: handling JSON responsibly

The issue

When dealing with GWT web apps, communication with the server is often done using GWT’s RPC implementation, which wraps nicely over the Java Servlet API, and encapsulates all the nitty gritty stuff such as object serialization and the like.

What they don’t tell you is that RPC has quite an overhead, which can build up as you recklessly add more and more services to your web-app. This overhead is acceptable, even desirable (no fuss of serializations), for handling Java APIs in the web-app’s server. It is, however, quite redundant when communicating with RESTful APIs, where another server will respond with JSON objects (data is already serialized).

The danger

Is when we start using GWT-RPC services as a boilerplate for any kind of communication, regardless of the remote server response type. There’s no sense in parsing JSON responses coming from a remote REST service back to POJOs in the web-app’s server — it will be parsed again to JavaScript as all code in the client package is essentially translatable java code.

The solution

Have the web-app’s server returning a JSON text response, request it via XHR on the client, and than use the response in its raw form — as JSON is a subset of JavaScript’s literal object notation, it can be used transparently within JavaScript code.

To implement this approach in GWT, create a servlet that returns the JSON as text (outputs it to the response’s writer). This servlet can than be called from the client using RequestBuilder (which wraps XHR), and overlay types can be used to convert each JSON response to Java managed objects on the client package, according to its contract.

Let’s assume the response for a certain call is:

{
    "foo": "bar",
    "fooList": [
        "firstItem",
        "secondItem",
        "thirdItem"
    ]
} 
  1. Create a servlet serving JSON:

    Don’t forget to configure the web-app’s deployment descriptor (web.xml) accordingly.

    public class JsonDataServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse res)
                throws ServletException, IOException {
    
            String responseText;
            // insert code to communicate with a remote REST service (perhaps using URLConnection), and fill responseText with data.
    
            // obtain a writer to send the result to the client
            PrintWriter out = res.getWriter();
            out.println(responseText);
            out.flush();
        }
    }
    
  2. Construct an overlay type according to the response’s interface:

    public class FooData {
    
        protected FooData() {}
    
        public native final String foo() /*-{
            return this.foo;
        }-*/;
    
        public native final JsArray fooList() /*-{
            return this.fooList;
        }-*/;
    }
    
  3. Create client side utilities to convert the JSON response to a concrete representation of a JavaScriptObject:

    public static FooData asFooData(String json) {
        JSONValue jsonVal = JSONParser.parseStrict(json);
        JSONObject jsonObj = jsonVal.isObject();
        FooData fooData = (FooData) jsonObj.getJavaScriptObject();
    }
    

    Notes:

    • Many resources suggest the use of eval() inside a JSNI method, but I prefer to utilize JSONParser.parseStrict() as it will first try and call JavaScript’s JSON.parse() on supporting browsers.
    • If you’re gonna use the eval() implementation anyway, the json argument needs to be wrapped in parentheses before evaluation, i.e. eval('(' + json + ')').
  4. Call the servlet:

    RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, GWT.getModuleBaseURL() + "path/to/servlet");
    rb.setCallback(new RequestCallback() {
    
        public void onError(Request request, Throwable exception) {
            // some error handling code here
        }
    
        public void onResponseReceived(Request request, Response response) {
            if (200 == response.getStatusCode()) {
                FooData fooData = asFooData(response.getText());
                // some code to further handle the response here
            }
        }
    });
    rb.send();
    

And voila! JSON all the way, no muss, no fuss.

Now you

What’s your take on this approach? have you done anything similar / have any suggestions / improvements? have you written a mind-blowing library that puts all this to shame?

Please share your thoughts.


Coming soon

How to create a custom JSON callback for RequestBuilder?

A VIDEO

yup. i’m on soundcloud now. finally.

A TEXT POST

Raphaël, my favored playground

cloudifysource:

A square could be anything, really

During the development on the GWT-based GUI for the Cloudify Web Management Console, we get to fiddle (no pun intended) quite a bit with raw JavaScript, to provide custom tailored solutions for various needs, like charting, graph-visualization or in-browser code editing.

It could have been an awful lot tedious were it not for Raphaël, as the bulk of our third-party library stack utilizes it as an underlying API for vector graphics manipulation. Its wide browser support and out-of-the-box event handling made it the obvious solution for native drawing, not to mention everything is accessible in the DOM as it renders to SVG or VML, which makes it perfect for Selenium testing.

Raphaël makes me feel nice and comfy, with its friendly API and acts as an amazing abstraction layer, turning what would have been a verbose, eye-sore of a markup into a 20-liner JS snippet.

Reblogged from Cloudify Engineering