GWT and Google Cloud Endpoints
Asked Answered
S

2

50

A few days ago I've started developing a Backend for Mobile Applications using Google App Engine and Google Cloud Endpoints. This tutorial shows how the endpoints are getting generated automatically, as well as the client library for Android.

So we have our Entity:

@Entity
public class Person implements IsSerializable{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;

    private String name;
//...
} 

And the endpoint for this class:

@Api(name = "personendpoint")
public class PersonEndpoint {

    @ApiMethod(name = "getPerson")
    public Person getPerson(@Named("id") Long id) {
...

Besides, using the generated Android Endpoint Library (that uses the REST API) I would like to add a User Interface on the Server, build with Google Web Toolkit (GWT). But how should I manipulate the date on Server Side? I can see different approaches...

Option A1: Adding an RPC Service in GWT

public interface PersonServiceAsync {

    void insertPerson(Person person, AsyncCallback<Person> callback);

}

@RemoteServiceRelativePath("api")
public interface PersonService extends RemoteService {

    public Person insertPerson(Person person);

}
public class PersonServiceImpl extends RemoteServiceServlet implements PersonService{
    public Person insertPerson(Person person) {
        EntityManager mgr = getEntityManager();
        try {
            if (containsPerson(person)) {
                throw new EntityExistsException("Object already exists");
            }
            mgr.persist(person);
        } finally {
            mgr.close();
        }
        return person;
    }

        //...
}

But now my PersonServiceImpl and PersonEndpoint do roughly the same. So we didn't follow DRY :) Besides, that Person is not allowed to have com.google.appengine.api.datastore.Key so we would have to change our Entities.

Option A2: Service calls endpoint class

@Override
public Person insertPerson(Person person) {
    return new PersonEndpoint().insertPerson(person);
}

Should work , but still no com.google.appengine.api.datastore.Key Type in the Entity and since Endpoints are using CollectionResponse<Person> we would have to transform this into an Collection<Person> in case of listPerson().

Option B1: Using the Java Endpoint Client Library

We could split the GWT Client from our App Engine API Backend and use the generated Endpoint Client Libraries for Java. So we call the REST/Endpoint-API from within a RemoteServiceServlet. But wouldn't this end up in two Requests, even if the GWT client and Endpoints are on the same server or even in the same project?

GWT Client --(RPC)--> GWT Server --(HTTP Request)--> App Engine Backend Server

Option B2: Using the JavaScript Endpoint Client Library

Might be the best approach but would end up in massive JSNI.


So what's best practice? I can't find any example projects using Google Cloud Endpoints AND GWT in one project :)

Subtemperate answered 28/5, 2013 at 7:51 Comment(8)
Have you seen code.google.com/p/gwt-google-apisCarrycarryall
Yes, but they are in an early Alpha Version and for the Google API. I'm talking about your own API/Endpoint, generated by GAE.Subtemperate
That library is for any discovery based API, which your API/Endpoint happens to be (discovery based, that is).Carrycarryall
I'm having the same dilemma. We are looking to use the Endpoint API but develop a GWT front end. I have a feeling it may have to be one or the other...Rame
Also looking for solution. Using JSNI for now.Ipecac
You could add to your path the com.google.appengine.api.datastore.Key class , it's not too elegant but worksHumphrey
Is it not possible to deliver webcontent trough the app.engine api? Why is it you need GWT?Starinsky
ORMs and Web 1.0 have made us Java Developers think that we could just get away with writing one class for everything. Providing data (to clients) and storing data are two different stories in reality. See my answer below.Preform
R
12

The good old DTO dilemma. There is no right or wrong, just what is good enough for you.

Repeating yourself can be a good thing. Right now you are exposing your data model through your endpoint, which means that any change of your Entities will impact your mobile app users. Let's say you rename an attribute on the server side -> every client who has not updated the app goes down.

Security is also an issue : if your User entity has an "email" property, serializing it through GWT RPC will make your user's email virtually available to any javascript debugger.

Is it really what you want?

Don't get me wrong, I'm not a fan of those "onion layers" monster apps where 80% of the code seems to be made to transform objects into other objets with virtually the same properties.

I think the right solution is in between: having a "client" model (DTOs), made of serializable POJOs (no datastore, ORM, JAXB, whatever annotation) that you expose through both GWT RPC and Client Endpoints. Your GWT servlet implementation and the Endpoint server would call the same service that will transform your client model into entities and process/persist them.

This way you can reuse your code, still keep it simple, have a uniform interface accross your APIs, and allow your inner plumbering to evolve without altering the client interfaces.

Reta answered 21/3, 2014 at 13:27 Comment(1)
Even though I didn't work with GWT for a long time, I ran more often in similar dilemmas (business model vs. DTO). Back in 2014, this answer didn't really satisfy me. But after a lot more years of experience with advanced Java development and thousands of code lines later I must say you exactly hit the point back then with your comment and I couldn't agree more with you.Subtemperate
T
0

Maybe i don't understand something. But everything seems (for me) to be very easy.

  1. GWT (client!) is not on the server. It is compiled Javascript executed in client's browser.

  2. Google plugin generates Javascript client code that calls Endpoint with suitable JSON.

  3. Above code can be called from GWT.

Voila?

Tawnytawnya answered 8/1, 2015 at 9:42 Comment(1)
Yepp, so this would be Option B2. But as I mentioned it would work but ends up in a lot JSNI. Because the most part of the Client is written/defined in Java (GWT), but the logic calling the endpoint is the generated Javascript code. Works but is not really nice.Subtemperate

© 2022 - 2024 — McMap. All rights reserved.