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.


Don’t get me wrong. I enjoy working with Endpoints, but there are always pitfalls to watch out for. Today, I’d like to focus on two limitations which affected the ultimate shape of my own API. These are primitive data types and references to the domain model.
Primitive data types (and void)
 
API methods cannot return primitive data types, only entities are allowed to be returned. Let me quote the docs:
 
A method return type as well as the request body of an API request must be an entity type.
 
The limitation probably stems from the fact that all the responses need to be clearly structured. Primitives, unlike entities, don’t let themselves to an easy transformation into JSON objects.
 
Implications? Well, my suggestion is always think data: What happens to my model if method X is called? – that’s the question you should constantly be asking yourself when shaping your API.
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]

Think “big” instead:

[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]

Domain model references

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]

Once you go and import the generated jars to a client code (an Android project for ex.), all of the sudden, you end up with two different flavours of Foo:

[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




Tomas Zezula

Hello! I'm a technology enthusiast with a knack for solving problems and a passion for making complex concepts accessible. My journey spans across software development, project management, and technical writing. I specialise in transforming rough sketches of ideas to fully launched products, all the while breaking down complex processes into understandable language. I believe a well-designed software development process is key to driving business growth. My focus as a leader and technical writer aims to bridge the tech-business divide, ensuring that intricate concepts are available and understandable to all. As a consultant, I'm eager to bring my versatile skills and extensive experience to help businesses navigate their software integration needs. Whether you're seeking bespoke software solutions, well-coordinated product launches, or easily digestible tech content, I'm here to make it happen. Ready to turn your vision into reality? Let's connect and explore the possibilities together.