Skip to content

morisil/autorest

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AutoREST for GWT

Maven Central Build Status Join the chat at https://gitter.im/intendia-oss/autorest

A source code generator for GWT compatible proxies from RESTful services (JSR311).

This project is a fresh start of RestyGWT removing everything related to encoding/decoding which now is delegated to JSON.parse and JSON.stringify. Thought to be used with JSO or JsInterop.

To keep the project simple only part of the JSR311 will be supported:

  • @Path (regex not supported and there is no intention to do so)
  • @HttpMethod (so all @GET, @POST...)
  • @PathParam and @QueryParam (other params will be supported)
  • @Consumer and @Producer are currently ignored (treated both and always as 'application/json')

Only RxJava types (Observable and Single) can be used as return value. This is mandatory to share the same interface between the client and the server, usually the server requires a synchronous return value but the client requires an asynchronous response. RxJava types allows to get both strategies using the same type.

Download

Releases are deployed to the Central Repository.

Snapshots of the development version are available in Sonatype's snapshots repository.

What is this for?

Creating REST services using JAX-RS annotations in a breeze, this is a minimal working example:

public class ExampleEntryPoint implements EntryPoint {

    @AutoRestGwt @Path("search") interface Nominatim {
        @GET Observable<SearchResult> search(@QueryParam("q") String query, @QueryParam("format") String format);
    }

    @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
    public static class SearchResult {
        public String display_name; //ex: "Málaga, Provincia de Málaga, Andalusia, Spain",
        public String lat; //ex: "36.7210805",
        public String lon; //ex: "-4.4210409",
        public double importance; //ex: 0.73359836669253,
    }

    public void onModuleLoad() {
        Nominatim nominatim = new Nominatim_RestServiceModel(() -> osm());
        nominatim.search("Málaga,España", "json").subscribe(n -> {
            GWT.log("[" + (int) (n.importance * 10.) + "] " + n.display_name + " (" + n.lon + "," + n.lat + ")");
        });
    }

    static ResourceVisitor osm() { return new RequestResourceBuilder().path("http://nominatim.openstreetmap.org/"); }
}

AutoREST will generate the proxy (Nominatim_RestServiceProxy) and you get the awesome RxJava API for free. If your have a java server side, you probably should try share the REST API (this is the whole idea), and if you are using Jackson too, you can get inspired by RxJavaJacksonSerializers.

How is done?

You define the JAX-RS service interface...

@AutoRestGwt @Path("orders")
public interface PizzaService {

    @POST Single<OrderConfirmation> createOrder(PizzaOrder request);

    @GET Observable<PizzaOrder> fetchOrders(@QueryParam("first") int first, @QueryParam("max") int max);

    @GET @Path("{id}") Single<PizzaOrder> fetchOrder(@PathParam("id") orderId);
}

And AutoREST generates the service model...

public class PizzaService_RestServiceModel extends RestServiceModel implements PizzaService {

    public PizzaService_RestServiceModel(ResourceVisitor.Supplier parent) {
        super(() -> parent.get().path("orders"));
    }

    @POST Single<OrderConfirmation> createOrder(PizzaOrder request) {
        return method(POST).path().data(request).as(Single.class,OrderConfirmation.class);
    }

    @GET Observable<PizzaOrder> fetchOrders(@QueryParam("first") int first, @QueryParam("max") int max) {
        return method(GET).path().param("first",first).param("max",max).as(Observable.class,PizzaOrder.class);
    }

    @GET @Path("{id}") Single<PizzaOrder> fetchOrder(@PathParam("id") orderId) {
        return method(GET).path(orderId).as(Single.class,PizzaOrder.class);
    }
}

This model map each resource method call all the way back to the root ResourceVisitor factory, create a new visitor, visits each resource until the end point is reached and ends wrapping the result into the expected type.

AutoREST evaluation flow

Everything looks quite simple, isn't it? This is important, keep it simple. If at any point something is not supported you can always implements it yourserlf. This project try to be just a boilerplate-reducer library, the unique actual logic is the com.google.gwt.http.client.RequestBuilder to rx.Producercode.

Response containers

This library is focused on JSON. So you should only expect 3 types of JSON responses, an empty/ignored body response, a JSON Object response or a JSON Array response. This tree types will match perfectly with the Completable, Single and Observable RxJava type, we call this the container. You are not limited to RxJava wrappers, but you should keep in mind this 3 containers so you codec will handle the response as expected. The synchronous counterpart of this 3 containers are Void, T and T[]. The next table shows the recommended response/container matching strategy.

Observable<T> Single<T> Completable
[…] T(n items) Error* Ignore
{…} T(1 item) T Ignore
other T*(1 item) T* Ignore
empty Void(0 item) Error Ignore

*Error: an JSON array should be handled by an stream wrapper (to keep things simpler), but you are in control of the codec, so you might support array types like String[], so Single<String[]> will return the JSON arrays in a Single wrapper.

*T: the "other" row represent "other values" like "some string" or 123. Again, it is recommended to only support T types where T is not a primitive (boxed or not) nor an array, but is up to you support this Single<Integer> or Observable<Float>.

*Ignore: completable will always ignore the response only notifing a successfully response or error otherwise.

About

Auto RESTful Service Proxy Generator for GWT

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 98.6%
  • Other 1.4%