Welcome to a Tutorial Series on Google Cloud Endpoints.
This series covers Google Cloud Endpoints with Eclipse.
If you are looking for using Google Cloud Endpoints with Android Studio, I recommend my series on Gradle, especially the following parts:
- Part 8 : Gradle + App Engine + Cloud Endpoints + Android Studio
- Part 9 : Gradle + App Engine + Cloud Endpoints (Persistence) + Android Studio
- Part 10 : Consuming Endpoints in your Android application
A Brief History of APIs
Public APIs are all over the place and ProgrammableWeb, the premier directory for public APIs reports that we are well over 10,000 public APIs. This is just the tip of the iceberg. The number of APIs that are private in nature or in other words undocumented and officially unavailable to us is probably 10x or 20x times that (I could be way lower in my estimates!).
Public APIs are now considered to be the most effective mechanism to integrate two applications. Typically the APIs are hosted in a Server side application and exposed to the clients to consume. The clients could be other server side applications, native mobile applications or even browser applications (mobile or desktop).
When we speak about a Public API, few things are common to them:
- They are available over a popular and well defined protocol, usually HTTP.
- It uses JSON or XML as the data format.
The above are not absolutely binding but the majority of the Public APIs have that in common.
Additionally, there has been a lot of debate over SOAP vs REST. I cannot get into the details of the two protocols and neither do I want to debate the pros and cons of both the approaches. Suffice to say that the currently predominant style is REST. REST makes use of various HTTP verbs in an effective manner to perform basic operations CRUD Operations or in simpler terms :
- List (or Get) All Records
- Get One or more Records based on some search criteria or ID(s)
- Create a Record
- Update a Record
- Delete a Record
One key point about Web Services is that it provides a great layer of separation between the client and the server in terms of the technology used. Client applications are completely agnostic to the programming language/environment that you are using on the Server side. HTTP is the common language that binds the two together and as a result, you could write your Server side API implementation in Java but still have the ability to invoke the same HTTP API via a Java client, iOS client or even a Web client.
Google Cloud Endpoints
The series of tutorials that I wish to cover, starting with this episode is focused around Google Cloud Endpoints, which is a solution from Google to help create a Public API for your App Engine application. Cloud Endpoints also provides facilities to generate client libraries for Android and iOS, thus easing your task to integrate your backend application functionality into your mobile applications on Android and iOS.
The diagram below shows the Cloud Endpoints solution (taken from the official documentation):
The point to note is that you need to have an App Engine application. Apart from that, how you store your data or retrieve your data is completely up to you. You could opt to work with the data store to meet your API functionality or simply talk to external services too to aggregate and present the response.
The tutorial series is more about the mechanics of Cloud Points, the toolset that Google provides rather than best practices around writing your API or API backend functionality.
This tutorial series will cover the following topics to give you a complete feel of the total solution:
- Part 1 : Overview and writing our first public API using Google Cloud Endpoints (We will be writing the API manually)
- Part 2 : Auto generate the Google Cloud Endpoints classes from your JDO/JPA class in App Engine.
- Part 3 : Using your Cloud Endpoints API in an Android app
- Part 4 : Using your Cloud Endpoints API in a Web Application
- Part 5 : Securing your API
- Part 7 : Calling a Secured API from an Android application
I might eventually end point combining one or more parts into a single blog post but we will leave that for another day. I might stumble along the way, but together we can and will cross over to the finish line.
What does this part cover?
In this part, we shall look at how we can write our API layer manually with the help of Cloud Endpoint APIs. By API Layer, we will write a REST interface that exposes our sample entity object (Famous Quotes) and provides API methods for Adding, Updating, Deleting and Searching/Retrieving Quotes.
Additionally, we will look at how to test your API locally and finally deploy it.
But why write the API manually? One could argue about why write the API manually since Cloud Endpoints does provide a mechanism to generate the API class from existing JDO/JPA annotated Entity classes. Well, it is important to understand this in detail too since it could help a lot in debugging when you face issues. And rest assured, in the next part, we will look at generating the API layer that we wrote here in an automated fashion and see the best in breed code that Google generates for the API class.
What do you need ?
- Basic understanding of Java Web Development, which includes Servlets, JSP, WAR file structure, etc.
- You have a working development environment for Google App Engine. This includes the Google Eclipse plugin.
My Development Environment
- Eclipse Juno
- Google Eclipse plugin with App Engine SDK 1.8.7
- Mac machine (but Windows will do too!)
Attention-> Cloud Endpoints became GA (General Availability) in Release 1.8.7 of the App Engine SDK. The latest release as of App Engine at the time of writing is 1.8.8.
Download Full Source Code
I suggest that you begin with a full download of the project source code.
Note: This is an Eclipse project that you can import directly. For the sake of reducing the code size, I have removed the App Engine SDK Jars from the WEB-INF\lib folder. So depending on the version of your App Engine SDK in the Eclipse development environment on your machine, please link to the appropriate App Engine SDK that you have for the project to build successfully.
If you are successful with importing the project into your Eclipse setup, the project directory should look something like this:
Our goal is going to be to write a public API that will allow us to manage Famous Quotes. I deliberately chose a Quote to make it easy for all of us to follow. A Quote is a famous/philosophical statement said by an eminent person.
“Be The Change That You Wish To See In This World.” – M.K.Gandhi
We will keep our Quote object simple. It will contain the following 3 attributes:
- id: A unique identifier for the quote in our system.
- author : The person to whom this quote is attributed to.
- message: The quote text.
Let us keep aside the API business for the moment. We will first model the Quote as a Java class. The class is present in the com.mindstorm.famousquotes.entity package and it also contain additional methods for equals/hashcode, etc. The source code Quote.java is shown below:
This section is not required as such but I am including it here so that we define both our interface and the implementation details for the different methods to handle Quote. So assume that you were not writing a web service or public API and had to create a Service class or Utility class to manage different operations like add, modify, delete and list for Quotes, then the class could look something like this.
The class is present in com.mindstorm.famousquotes.service package and the file name is QuoteService.java. The code is shown below:
Let us discuss a few things here since they are important:
- The QuoteService class contains methods for add, update, delete, get, search and so on.
- The implementation of these methods has been kept simple and you should be able to understand what is going on.
- Pay special attention to the signature for each of the methods because that has a role to play later on in the article because Google Cloud Endpoints does look for specific signatures to help map the different operations to HTTP methods like GET, PUT, POST and DELETE.
- The add method typically contains the different attribute fields as the parameter and returns back the Quote object that was successfully added to the list.
- The update method has the Quote object that needs to be updated, as the method parameter. This means that the id, author and message attribute needs to be populated correctly in the Quote object that is passed as the parameter. This method too returns the Quote object that was update.
- The remove method takes an Id as the parameter for the Quote that needs to be removed and has no return type.
- The get* methods are used to retrieve one or more Quotes that match as criteria as needed. Notice that the return type is a List of Quotes.
- Also note that we are throwing back the normal java.lang.Exception object, in case of any issues.
Hope this makes things clear on how we would have written a standard Java class to help work with the Quote entity and manage the Quote collection.
Converting it to a Google Cloud Endpoint class
Now, let us think for a moment for what we would need to do in order to expose the above service as a REST API.
At a high level, we will need to do the following:
- Identify how we will map the different methods to the equivalent HTTP Verbs. In order words, as per best practices in REST APIs, we will need to expose the get* methods over GET, the update method over PUT, the add method over POST and the delete method over DELETE verbs. Sounds good ?
- Additionally, we also need to make sure that we are throwing back the correct HTTP Response Codes. You would have heard about HTTP 200 for OK, HTTP 404 for Not Found, etc. So for e.g. if we try to update a Quote for which the Quote ID is not found, we need to make sure that we are passing back the correct HTTP Error code say 404 NOT FOUND. You will find public APIs that don’t follow this strictly but it is good practice.
- Once we have all this in place, we need to figure out how to test this API.
Given the above points, let us see first how to convert our existing QuoteService.java file to a Cloud Endpoints class that will help expose the REST API. You will find that it is all about using the correct annotations, Exception classes from the Cloud Endpoints libraries and some magic that Endpoints does behind the scene based on your method signatures.
Let us look at the converted class with the API Annotations. The Java class is present in com.mindstorm.famousquotes.service package and the file is QuoteServiceAPI.java. The source code is shown below:
Let us go through the important points:
- We have replaced the java.lang.Exception class with the NotFoundException class that is part of the Cloud Endpoints classes. The NotFoundException class will throw the correct 404 response code and details, as we shall see. Look at the entire set of Exception classes that Cloud Endpoints exposes : Exceptions and HTTP.
- To identify this class as the API class, we have used the @Api annotation right on the top of the class as given below:@Api(name=”quoteapi”,
description=”An API to manage famous quotes”)
We provide a name to our API, a version and also a description. If you do not provide these, default values will be taken but we will specify them here. Actually this is all that we need to do since Cloud Endpoints can then take all the public methods of the class, weave its magic based on the method signatures and expose the methods over HTTP verbs respectively. But we will be more specific as explained below.
- Each method, we are annotating with the @APIMethod in which we are providing a name to the API method. Each method parameter that we want to the API Method to consider, we are used the @Named annotation where we specify the parameter name that will be actually used by the client while passing the value to it. We are keeping things simple for now, but if you are interested in the entire range of annotations, take a look at Annotating your API.
- Notice that we did not specify which HTTP method (GET, POST, PUT, DELETE) is mapped to which Java method. It turns out that Cloud Endpoints does some clever behind the scenes work where it will use the correct HTTP methods. It seems to do that based on what key words a method starts with, the method signature, etc. From my findings, it is doing so on method signature but conceptually you should follow the general rules of thumb given below (taken from their documentation). You should ideally follow this best practice for beginning your method names with the key words listed below, it will makes things easier to understand for everyone. Do note that if we want we could still specify the HTTP Method to use via the @APIMethod annotation. The attribute httpMethod can be used to specify GET , POST, etc.
We are done with our API ! Simple … wasn’t it ? Yes, but how do we test out the API and see the raw HTTP Request / Responses that move back and forth.
Testing your API Locally
Now, comes the fun part and indicates the amount of work the Google Developers have put in to make it easy for you.
Follow these steps:
- Make sure your Project is ready, compiles fine without errors. Run your Application.
- Assuming that your Web Application starts on port 8888, Visit the following URL: http://localhost:8888/_ah/api/explorer
Make sure you are connected to the Internet. If all is well, you will see an API Explorer as shown below:
How did something get exposed over the _ah/api endpoint. Well, visit your web.xml and you will find an entry created out there for you, which behind the scenes will invoke the API logic for you.
You will notice that the explorer has used our @API (name, version and description) as we provided.
Cool, now lets click on the quoteapi link, this will bring up a list of all our API methods. Notice that the method names were taken as the ones that we provided in the @APIMethod annotation.
Now, lets add a Quote. We will click on quoteapi.add link. This will bring up a form where we can provide the id, author and message for the Quote as shown below:
Clicking on the Execute button will actually make the call and what is interesting to note is that behind the scenes a HTTP POST call is made. Take a look at the HTTP Response too, where the return object type i.e. Quote is marshalled correctly into a JSON object.
Go back to the list and click on the quoteapi.list method. This will invoke a GET as shown below and return the collection as a JSON response.
Now, let us look at quoteapi.getQuote method where we need to provide the id field to retrieve the record. The API explorer brings up the form as shown below. We provide the id as 1 (for our only quote so far) and it fires a GET and retrieves the data.
Pay attention to the entire GET format too to better understand the format. You will notice that the format is _ah/api/<APIName>/<APIVersion>/<Object>/<ID>
Now, look at what happens if we provide an id that does not exist.
Since a Quote record with id = 2 does not exist, it throws a NotFoundException which behind the scenes gets converted into the correct HTTP Response 404.
If we invoke the quoteapi.update method, it will open up a form where we can enter construct the Quote object that we want to modify. We will provide the same id but different values for the message as shown below:
If we retrieve the list of quotes, we will find the updated data:
Finally, let us look at quoteapi.remove method shown below (In my sample data I added a second record too so I am deleting here with id = 2). Notice that it fired a DELETE HTTP command and since we did not return any type, it sent back a 204.
This brings us to the end of this episode. In this episode, we saw how simple it was to use the Google Cloud Endpoints library to expose a public API. You can go ahead and deploy the same to a live instance too, things should work seamlessly.
In the next part of this tutorial, we are going to take a look at how we could take an existing JDO/JPA annotated Entity object and ask Google Cloud Endpoints to generate the API for us, instead of us having to write it by hand as we saw in this tutorial. But our basics here will help us understand better the code that it generates.
Hope you liked the episode. Till the next one, Happy “API”ing … !