Google Cloud Endpoints – Design Considerations
While designing of the Endpoints API is fairly straightforward, there are gotchas one might stumble upon. Especially when task at hand is slightly more involved than the proverbial “hello world” example. It took several iterations in my tiny little project to adjust the API according to my needs.
Forget about efficient response types:
[java]
// Return id of the persisted object
public Long saveFoo(@Named(“name”) String fooName) {..}
// True if the operation succeeds, false otherwise
public Boolean deleteBar(@Named(“id”) Long barId) {..}
[/java]
[java]
// Return a new entity
public Foo saveFoo(@Named(“name”) String fooName) {..}
// Return a list of remaining items
public List<Bar> deleteBar(@Named(“id”) Long barId) {..}
[/java]
Using void as a way of skipping a meaningful response proved problematic too. Again, there is nothing essentially wrong with it, except for the fact it results into HTTP 204 (no content):
[java]
// Who cares about the output, let’s just give it a shot
public void addFoo(@Named(“name”) String fooName) {..}
// Upon a successful(?) completion
POST http://localhost:8080/_ah/api/helloworld/v1/addFoo/test
204 No Content
[/java]
Splitting your API implementation into several classes might make a lot of sense. There are many reasons for why it sounds like a good idea. Separation of concerns, clearly defined responsibilities, high modularity to name but a few.
There is a slight problem though if a given domain class is shared among two or more API modules. Let me set a quick example:
Domain model – a single class called Foo
[java]
package com.example.domain;
public class Foo {
private String name;
..
}
[/java]
API comprises two independent classes FooApi and BarApi. Please note that both of them deal with Foo.
[java]
package com.example;
import com.example.domain.Foo;
@Api(
name = “fooApi”,
version = “v1”,
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE}
)
public class FooApi {
public List<Foo> listFoo() {..}
}
[/java]
[java]
package com.example;
import com.example.domain.Foo;
@Api(
name = “barApi”,
version = “v1”,
scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE}
)
public class BarApi {
public List<Foo> listFooBecauseICan() {..}
}
[/java]
[bash]
$ mvn appengine:endpoints_get_client_lib
..
fooApi/target/fooApi-v1-1.19.0-SNAPSHOT.jar
barApi/target/barApi-v1-1.19.0-SNAPSHOT.jar
[/bash]
[java]
import com.appspot.phrasal_period_801.fooApi.model.Foo;
import com.appspot.phrasal_period_801.barApi.model.Foo;
[/java]
To sum up, there is no problem in splitting the API into as many standalone implementations as needed. However, I’d recommend not to refer to a given entity from more than a single API class.
This post is part of Google App Engine and Android – Pros and Cons, Challenges