Skip to content

Digging into Cloud Endpoints: building a RESTful API.

Google Cloud Endpoints (CE) is GCP’s solution to build a RESTful API. It works great, although there are also a few gotchas that I’d like to share with you. (Note that this is NOT an article about CE v2 that is currently in beta.)

Let’s see how to build a simple API that adds, retrieves, updates and removes cars. We will use Google App Engine, GCP’s Platform as a Service, as our backend solution. (Note however, that this is not an introduction to App Engine.)

The examples provided in this article are written with Java 7 and are in no way supposed to represent a real-world project but rather have been simplified for the sake of keeping it easy to follow along.

Setup

This is what the class “Car” looks like:

ceblogimage1

The class that handles the actual CRUD operations will be the CarService”. Note that we will use a simple HashMap to store our cars by “id”.

ceblogimage2

Let’s start with writing the code for a simple endpoint that returns a Car. First we have to use of the @Api annotation, to tell CE that we’d like this class to represent an endpoint.

ceblogimage3

While there are a lot of options for @Api, there are only a few that we’re interested in at this point:

  • Description: is used by client libraries such as the API explorer to describe your AP
  • Name:  is used as a prefix for for all of the API methods and paths. 

Another interesting one is “clientIds” which handles OAuth2 authentication with your API, though we will not make use of it in this example.

Testing our API

In order to test our API we use the API explorer, a handy tool that runs on our local App Engine development server ( /_ah/api/explorer) and allows us to do test calls to our API without writing any client code or having to browse to the endpoint paths directly.

When we browse to localhost:8080/_ah/api/explorer” we should now see our API up and running:

ceblogimage4

But wait, how come the “getCarById” is there? Don’t we have to do something to tell CE that we’d like this method to be exposed to the outside world?

It turns out we don’t, there’s an @ApiMethod annotation that lets us define how we want our method to be exposed, it’s entirely optional and if omitted CE will “guess” how we want our method to look like. We will explain this more in depth later, for now let’s be explicit in exposing our method and make use of @ApiMethod.

ceblogimage5

The 3 properties we’re interested in:

  • Name: Same as in @Api but for the method name itself
  • Path: will be appended to the path at which our API will be exposed. Note that you should NOT start this path with a ‘/’, as that will override the prefixed path of our class and will not work
  • HttpMethod: The HTTP Method, the name of this method. The ones that are most useful for building API’s are GET, POST, PUT and DELETE (and perhaps PATCH)

Let’s test our API method by getting a car with the id of 1.

As you can see, it looks good! CE takes care of serializing our Java class to a JSON object. Our method is named “carEndpoint.getCarById” in the API explorer, which sounds like a reasonable name. We sent a “GET” request to our endpoint at the url ending with /carEndpoint/v1/car/1″ and got the expected response.

Let’s add a method to save cars to our API.

ceblogimage7

When we look at our request, we see the car object has been added to the body of our request, as we expected.

ceblogimage8

In the docs on parameters and return types we’re told that entity types will be put in the body of our HTTP request. @Named on the other hand is used for path or query parameters.

Let’s add a method for removing cars, and this time, we will rely on all the defaults that CE generates for you if you don’t use @ApiMethod.

ceblogimage9

We will remove the car with id 1.

There are a few things we can see here:

A name was generated, more specifically the name of our @Api (carEndpoint), a dot ‘.’ and the name of our method. While the name of the method is probably what you want most of the time, I don’t think the @Api name is necessary since we’re just repeating ourselves here.

The path to which our request was sent ends in /car/{id}”. This is perfect! Possibly the car part was deduced from the method name removeCar?

The HTTP method is DELETE, which is also perfect, how did CE know that?

Digging deeper

Let’s investigate points 2 and 3 here. First off, we will name our method “removePepperoniPizza” to check if we were right in thinking that the second part (camelcased) of our method name is used as the path.

ceblogimage11

Looks like we were right! CE will use everything after the first word to generate our path. Could it be that CE uses the first word to determine the HTTP method? Let’s check it out:

ceblogimage13

ceblogimage14

Turns out we were right about that as well! One odd thing to notice is that the path name is now void/{id}”, possibly this is because CE generated a GET method for a method that doesn’t return anything (void), which doesn’t make any sense.

Let’s fix our method and explicitly annotate it:

ceblogimage15

Now, what if we don’t want to remove our car from our Map but instead want to put it on “inactive”? A lot of companies don’t want their data to be removed forever, but would rather see an inactive flag that restricts the item from being retrieved. Let’s add a method for that in our CarService”:

ceblogimage16

We added a check to make sure that we do not accidentally add new cars that are instantly deactivated. We will modify our endpoint to call this method instead.

ceblogimage15

Since we’re now actually updating a car behind the scenes and not really removing it, we are handing the endpoint our Car object.


We got an IllegalArgumentException! How did that happen? Let’s debug our code and take a look at the Car object we’re receiving:

ceblogimage19

All our properties have been set to their default values! When we take a look at this SO answer, this is actually expected behaviour, servers should remove the body of a DELETE method.  Simply altering the method to PUT will make this work again:

ceblogimage20


We’ve also renamed the method to reflect our intentions more correctly. I think it’s a good thing that CE removes the body of HTTP requests that use the DELETE method (and so probably also the GET method), however, if we hadn’t put that check for the car’s id before deactivating it, we might have ended up with a very nasty bug where cars would never get deactivated.

Personally, I think it probably would have been better if CE had thrown an exception if it saw a DELETE/GET method that had a request body defined.

Despite a few of these somewhat odd design choices (defaults, removing method bodies) I think CE is the best REST API solution out there if you’re running your application on App Engine: generating client libraries, for languages such as JS/Android/iOS, and testing your API with the API explorer has never been easier. In a future blog post we’ll take a look at CE v2 which, among other things, adheres to the OpenAPI specification.

If you’re eager to learn more, check out the docs.

You can find the source code to the complete example here

Written by Robin Hellemans