TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and former Developer Advocate with Google now residing in Colorado. Besides tech, I enjoy landscape photography and share my work at ColoradoPhoto.gallery.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 241 other followers

  • Sleepless Nights…

    July 2014
    S M T W T F S
    « Jun   Nov »
     12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
  • Blog Stats

    • 853,427 hits

Painless REST+JSON API with Jersey and RestyGWT

Posted by David Chandler on July 23, 2014

It’s been a while since I’ve been active in GWT programming, but I recently picked up an old GWT + App Engine project and dusted it off. This time around, I need a service layer that will work with native mobile apps as well as the GWT desktop app: in other words, a REST+JSON API.

The server side

I decided to use Jersey on the server, which makes it incredibly easy to create REST services, especially in combination with the fabulous objectify-appengine. Here’s one of my services:

@Path("api/user")
@Produces(MediaType.APPLICATION_JSON)
public class UserDao extends ObjectifyDao<User>
{
    @GET
    @Path("me")
    public User getMe() {
        return AuthFilter.getUser(); // long live ThreadLocal!
    }
}

All the other standard CRUD methods (list, get, delete, etc.) are inherited from a generic DAO. A servlet filter verifies user authentication, XSRF tokens, etc. At only one class per entity, I find this much more agreeable than the four classes per entity I used to write with gwt-dispatch (Action, Result, Handler, DAO).

The GWT REST+JSON client

On the client side, GWT developers have long needed something which combines:

  1. The convenience of GWT-RPC (automatic serialization of pretty much everything)
  2. JSON data format
  3. Simple verb-based service APIs
  4. Benefits of the command pattern such as request caching and batching
  5. Minimal boilerplate

RestyGWT delivers on all counts.

The interface is actually simpler than GWT-RPC because you don’t have to define a synchronous and asynchronous method, only async (although you can reuse the server interface and call it using DirectRestService if it helps you sleep better). Here’s a sample interface using RestyGWT. This is a generic CRUD API which I simply extend for each entity class.

public interface RestApi<T> extends RestService {

    @GET
    @Path("own")
    public void getForOwner(MethodCallback<T> callback);

    @GET
    @Path("get")
    public void get(@QueryParam("id")Long id, MethodCallback<T> callback);

    @GET
    @Path("all")
    public void listAll(MethodCallback<ListResponse<T>> callback);

    @POST
    @Path("save")
    public void save(T obj, MethodCallback<T> callback);

    ...
}

Here’s a sample service API and the GWT code that calls it:

public class UserPrefsService
{
    private static final UserPrefsRestService service = GWT.create(UserPrefsRestService.class);

    @Path("/api/userPrefs")
    public interface UserPrefsRestService extends RestApi<UserPrefs> {
        // just in case you missed it, all the CRUD methods are inherited
    }

    private UserPrefs prefs;

    public void loadUserPrefs()
    {
        service.getForOwner(new AppCallback<UserPrefs>() {
            @Override
            public void handleSuccess(UserPrefs result) {
                prefs = result;
                App.getEventBus().fireEvent(new UserPrefsLoadedEvent(prefs));
            }
        });
    }
}

I really like the benefits of the Command pattern from the old gwt-dispatch framework such as the ability to do caching and queuing centrally. The downside of the Command pattern is the proliferation of classes associated with turning every API method into two or more classes (in the case of gwt-dispatch, an Action and Result class for every service method). GWT’s RequestFactory (the GWT team’s “final answer” to RPC after GWT-RPC and deRPC) used generators to remove some of the boilerplate, but I wasn’t in love with having to call someSingleton.getRequestFactory().someRequest().create(BeanProxy.class) each and every time I wanted a new Bean. And it uses a proprietary data format, not REST+JSON.

This is where RestyGWT really shines. It lets you define simple API interfaces using methods, but uses a Command pattern dispatcher under the covers with an ingenious filter mechanism for adding capabilities like XSRF protection, caching, and retries. The magic is possible thanks to RestyGWT’s generator classes which transform your annotated service methods into MethodRequest classes that get sent by a dispatcher. To add caching capability to all your APIs, for example, just put this in your GWT onModuleLoad():

DispatcherFactory factory = new DispatcherFactory();
org.fusesource.restygwt.client.Defaults.setDispatcher(factory.cachingDispatcher());

For a look at some of the other dispatcher options, have a look at the RestyGWT User Guide and the example DispatchFactory class.

Tips for success with Jersey + RestyGWT

Just a couple final notes to ease your migration to Jersey + RestyGWT.

If you’re using RestyGWT with Jersey + Jackson on the server, you’ll want to set the default date format to avoid Date serialization errors. Put this in your GWT’s onModuleLoad():

Defaults.setDateFormat(null);

Similarly, recent versions of Jersey complain about “self-referencing cycles” or some such with Objectify’s Ref properties, so you’ll probably want to annotate those in your server-side entities with @JsonIgnore. If you need the id of a related object, use a differently named getter instead. Jersey will create a corresponding JSON property. Example of an Objectified entity on the server:

package com.my.server.domain;

@Entity
public class UserPrefs {
    @Id
    private long id;
    @JsonIgnore
    private Ref<User> ownerKey;
    ...
    public long getOwnerId() {
        return ownerKey.get().getId();
    }
}

Then on the client you can reference the ownerId property:

package com.my.client.domain;

public class UserPrefs
{
    public Long id;
    public long ownerId;
    ...
}

I would prefer to use the same object representation on client and server, but RestyGWT makes using DTOs about as painless as possible. The client-side object is a class not an interface, so you can create a new instance anywhere you need it vs. having to GWT.create(BeanProxy.class). I could probably hack Jersey and maybe objectify-appengine to automatically replace all Refs with a long id, but honestly, it’s easy enough just to copy the server entities and replace Refs with long ids on the client.

Also, here’s a pair of classes you may find useful for sending any type of list from server to client. For security purposes, a JSON response should always return a root object, not an array directly. The ListWrapper (server) and ListResponse (client) serve as this root object, having a single field containing the list.

package com.my.server.domain;

/**
 * Wraps a List<T> in a JSON root object.
 */
public class ListWrapper<T> {
    private List<T> list;

    public ListWrapper(List<T> list) {
        this.list = list;
    }
    public List<T> getList() {
        return list;
    }
}

Use it like this in one of your Jersey-annotated methods:

    @Path("all")
    @GET
    public ListWrapper<Subscription> findAll() {
        User user = AuthFilter.getUser();
        List<Subscription> userAll = this.listByOwner(user);
        return new ListWrapper<Subscription>(userAll);
    }

Using ListWrapper this way has the additional advantage of causing Objectify to fetch any lazily loaded properties such as Refs used in the getOwnerId() method above while producing the JSON. If you were to return the List directly, this would not occur!

Here’s the corresponding representation on the client:

package com.my.client.domain;

public class ListResponse<T> {

    public List<T> list;

}

See the RestApi example earlier for how it’s used.

Summary

Jersey and RestyGWT in combination make a powerful and easy way to create a REST API for your GWT client and mobile apps, combining all the benefits of a request dispatcher with straightforward service interfaces and minimal boilerplate.

Happy coding!

9 Responses to “Painless REST+JSON API with Jersey and RestyGWT”

  1. Rutger said

    Nice! Will try that out myself.

  2. Using Jersey on the Server side and Lombok during development, I’ve saved countless hours. Thanks for the GWT tips, those were new to me!

  3. Hey David, thanks for the blog. Could you help out by sharing a sample project with AuthFilter etc.?

    • Yes, I definitely plan to at some point. I have actually thought of offering sample projects for $99 like MyApps does. Would you be willing to pay for access to the source code of a complete sample project?

      • Arpit said

        Good idea! If it has features I need, then why not!

        What I need right now is –
        1. Custom Authentication
        2. Objectify Support (this one should be easy to do for me as well but great if it is built in)
        3. Get/Put/Post/Delete using Resty with some frontend code using GWT Editors.

        It’s tough to find a Resty GWT sample on internet which runs out of the box.
        I’ve tried creating a sample which includes 2 and 3 but it’s still far from perfect.

  4. Bademus l. said

    What you think about https://github.com/ArcBees/GWTP/wiki/Rest-Dispatch
    Thank you.

  5. Pooch said

    Great stuff!

    You wrote: “GWT’s RequestFactory (the GWT team’s “final answer” to RPC after GWT-RPC and deRPC) used generators to remove some of the boilerplate, but I wasn’t in love with having to call someSingleton.getRequestFactory().someRequest().create(BeanProxy.class) each and every time I wanted a new Bean. Also it’s been deprecated.”

    Can you point me to the announcement stating that RequestFactory has been deprecated, please? I don’t see it as being deprecated here: http://www.gwtproject.org/javadoc/latest/deprecated-list.html and it is alive and well here: http://www.gwtproject.org/javadoc/latest/com/google/web/bindery/requestfactory/shared/RequestFactory.html.

    Thanks

    • Yikes, my bad! RequestFactory is not deprecated. It is less well supported because the two original authors (Ray Ryan, Bob Vawter) no longer work on GWT (nor at Google); however, as long as GWT community superstar Thomas Broyer continues to use it in his projects, RF should be fine 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: