All things software!

Google Cloud Endpoints Tutorial – Part 2

Welcome to Part 2 of the Google Cloud Endpoints Tutorial.

The full series:

Part 1 : We looked at writing a Google Cloud Endpoints class manually by using the various annotations and Exception classes that are available. We create a Quotes API that provided a JSON + REST based interface to manage Quotes (add, modify, delete and retrieve quotes).

Part 2 : We generated the Google Cloud Endpoints class from a JDO Annotated Entity class by using the Code Generation tools provided in the library.

Part 3 : Generated the Cloud Endpoints Client Library for Android and wrote an Android application that invokes the Endpoints API.

In this episode

In this part of the series, the end goal for us is the same i.e. to generate the Quotes API. However, we shall let the Cloud Endpoints classes do the magic for us by helping us generate the API Endpoint class, instead of us writing it by hand.

What do you need ?

You have a working development environment for Google App Engine. This includes the Google Eclipse plugin.

You do not need to be an expert at JDO or JPA. We shall be using some JDO annotations for our Entity class to allow it to declare itself as being available for persistence and what attributes of the class is a key and should be persisted. Just follow the tutorial along the way and you will be just fine.

My Development Environment

This remains the same, no changes at all. My development environment is given below:

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.

Create App Engine Project

The first thing we will do here is to generate a new App Engine project. Let us not disturb anything that we did with the project from their previous part of this tutorial series.

In the Project name, choose a suitable name. I have named my Project : MyAPIProject2. For the package name, I have provided com.mindstorm.famousquotes. Deselect the GWT option. Leave the other options as default. Click on Finish.

This will generate the App Engine project for you.

The Entity Class – Quote.java

The next thing we are going to do is write our Quote class. This class is similar to the one that we saw in the previous episode. I have stripped it down further by removing the hashcode/equals/etc methods from the class to keep our focus clear.

The Quote entity still has 3 main attributes : id, author and the message.

What you will find different here is that the class is JDO Enabled. Take a look at the full source code for the JDO enabled Quote entity class and we will discuss further.

Let us discuss the main points:

We mark our Quote class for Persistence via the @PersistenceCapable annotation. This is done right at the top of the class declaration.

Each attribute of the class that we would like to persist is marked with a @Persistent Annotation. If you do not want to persist any specific attribute mark it with @NonPersistent. But in our case, this does not arise.

We need to specify which attribute is the Identifier Key i.e. which can be used to uniquely identify a specific record in the datastore. In our Quote class, the Id attribute will always have a unique value for each record, hence we give it an additional annotation @PrimaryKey.

Notice that for the Id attribute, we have also provided an additional attribute for the @Persistent annotation. We have specified that a valueStrategy and the value of which says that the underlying JDO implementation will take care of providing it a unique ID. What this means is that when we want to persist a Quote object, we will simply have to construct the Quote object and populate its author and message attributes. The Id value will be filled up appropriately for us at the time of persistence.

Make sure that you have saved this class, before moving on to the next step.

Generating the Quote Endpoints class

Now that we have our Quote JDO Entity class in place, we are going to tell the Endpoints library to help generate the Endpoint API class, with the full JDO implementation such that we do not have to worry about writing the code that deals with the Datastore API, that App Engine provides.

Let us generate the API Endpoints class now. To do that, do the following:

Right-click on the Quote class in your Eclipse IDE and select Google -> Generate Cloud Endpoint Class as shown below:This will generate a couple of Java classes for you in the same package that your Quote Java class is present in.

The 2 files generated are PMF.Java and QuoteEndpoint.java. The QuoteEndpoint.java is of particular importance to us and it contains the Endpoints class.

Take a look at QuoteEndpoint.java. If you have followed Part 1 of the tutorial, you will notice that the method signatures if not the method implementations look familiar. They contain the usual methods for inserting, updating, deleting and fetching Quotes, almost similar looking to the ones that we wrote by hand.

At this point in time, you could actually just Build your project and Run the Web application and the API will be available to you if you navigate to the _ah/api/explorer endpoint in your local browser. You can try out the method for the QuoteEndpoint and not worry about what happens behind the scenes but you will only get so far, hence we will get into the details of what the code is doing and in fact, even correct a problem or two with the generated code.

Lets move on.

Dissecting the generated Quote Endpoints class

If you look at the QuoteEndpoint.java class that has got generated, you will find the following methods that it generated.

The Green circle indicates public methods, which means that the methods will be exposed by the API Endpoint. A couple of methods are private methods here and are used by the other methods.

The getPersistenceManager() private method is used to get an instance of the PersistenceManager implementation. The second Java file (PMF.java) that was generated for you, contains the details for getting the instance. This is standard boilerplate code for getting a handle to the Persistence Manager in the JDO/JPA world.

OK. Over to the API Endpoint methods now. These are all the public methods in the class. Just a side note that if you plan to enhance the functionality and need to write your own methods but do not want to expose them as API methods, do remember to mark them as private.

The entire source code for the QuoteEndpoint.java file is shown below. In fact I did modify the code slightly to make it work for me in the way that I wanted and I will discuss that in the next section (Modifying the Source Code)

The main points to note are:

Note the @API annotation used at the top to identify that this is an API class. The namespace stuff is used when we generate our client libraries and we will look at that in the next tutorial or two but for now, don’t worry too much – though you will be able to understand that it uses your package names from the project.

Each of the methods should be understandable now to you based on our learning from the previous part. Each of the public methods that need to be present in the API are annotated with the @APIMethod annotation. A name attribute specifies the name of the method.

Pay attention to a new annotation used for parameters passed to the public API methods. The annotation is @Nullable and it means that it is not a mandatory parameter to be passed.

The method implementations are not difficult to understand. Each of the method implementations simply gets a handle to the persistence manager, then performs appropriate DB operations for get, update, insert , delete and then closes the persistence manager object, so that the operation can be committed by the Datastore implementation.

Important point :
The method signatures that you see here are generally regarded as Best Practices for a REST API. You can always debate for example, if you want to pass a Quote object to the insert method or you want to pass individual parameters i.e. author and message.

The point is that nothing stops you from following a style that suits you. So there is a lot of flexibility that is available here from an interface point of view. You decide if the method names need to be different, if you would like to use POST instead of GET, if you want individual parameters instead of the whole Quote object and so on. Just refer to the full Annotation documentation and understand them better.

Modifying the Source Code

Just to demonstrate that things are flexible and that you might not find the Google code at times, appropriate to your functionality – I modified the generated code a bit.

Refer to the insert method shown below. The parameter to be passed is the whole Quote object and while inserting a new record, remember that we had discussed that we will only pass the author and the message attributes. We will keep the Id field empty or not provide it since we would like the Id generation strategy to be automatically handled by the JDO implementation.

The original code did not have the check that I have added in bold and as a result, the API implementation was crashing if I provided a new Quote object to be added without providing the Id (which I did not want to provide in any case).

In the next section, you will observe that I do not pass the Id value when using the insertMethod.

Testing out the API

You can test out the API in the same fashion i.e. via the API Explorer, which is also available locally.

We will keep our testing limited to a call or two, since I am assuming that you are comfortable with it now.

Click on the Quote Endpoint and you will find a list of methods. Specifically, let us click on the insertQuote method.

This brings up the screen as shown below:Notice that we are populating only the author and the message attributes. We are not providing the id, since we want that to be system generated and unique and the underlying JDO implementation handles that for us.

Click on the Execute button and it should insert the record successfully for you. The sample run from my system is shown below:

You can try out the other API methods if you want. They should work well.

Datastore Viewer

Since the code generated works with the Datastore, every successful INSERT of a Quote record will end up as a record inside the App Engine Datastore. You can validate this within your local development environment too.

Then visit http://localhost:8888/_ah/admin i.e. the normal Administration console URL in your browser. If you visit the Datastore link, you should see an entity Quote available and you could take a look at the different records. An example screenshot from my environment is shown below:

Some comments

Cloud Endpoints generates for us a Endpoint Java class. This should not be taken as the final class that we should not or cannot modify. You had learnt in the first part of the tutorial about the different annotations and method parameters. You are free to change any of the generated class code to suit your API style and requirements.

The code that is currently generated for a JDO/JPA Entity class works with the App Engine Datastore service. So if you are not planning to use this infrastructure service in your application, then you will need to modify the Endpoint class accordingly.

The generated code is by no means production ready and you should build in your own validations and Exception classes as needed. For e.g. it is good practice to make sure that all the request parameters contain valid values before you go ahead with any of the operations. In the code that we modified, we simply put in an additional check to see if the ID is provided, etc. But I would even go further and make sure that valid values for Author and Message are provided. Only then would I go ahead and do any persistent operations , else I would just reject the call there itself with the appropriate Exception.

Download Full Source Code

I suggest that you begin with a full download of the project source code.

61 thoughts on “Google Cloud Endpoints Tutorial – Part 2”

FWIW you don’t need plain “@Persistent” on String fields, or indeed the vast majority of fields, only needed if the type is not a commonly used type, or you want to specify other attributes with the annotation. You also don’t need “identityType = IdentityType.APPLICATION” since you’ve annotated a field as @PrimaryKey so have to use application identity.

First of all, thank you very much for your great tutorials. I have two questions and wonder if you could please help.

1) The Google cloud endpoints library generated comes with the standard sets of CRUD APIs, for e.g. list all quotes with ‘listQuote’ API. What if I want to add predicates to listQuote and select certain quotes filtered by the predicates? How do I do it?
2) Similarly, instead of updating the entire Quote row with the standard cloud endpoints API ‘updateQuote’, can I update the Author column only?

I believe both of the points that you have mentioned are possible. All you need to know if modify the Datastore API related code to do what you want i.e. filtering and updating certain attributes for the Datastore entity only.

I have in my DataStore 2 Entities more specifically the Entity1 with a @Unowned Relationship to Entity2 (in my case i used a java.util.List of entity2 objects). When i create the Endpoint showing the Entity1 i can only see simple fields (String, Integer…). How can i create a more complex List, or better, how can i fix this issue in order to see all the fields of my Entity Class? Thank you so much

1. Are you saying that you are able to see only simple fields of Entity1 in the API Explorer ? If yes, something looks missing since if there are other entities specified in the JDO Entity object, they do show up.

2. Please check if you have not forgotten to regenerate the EndPoints after you have changed the Entity definition ?

3. For e.g. try to create one Entity1 and inside of that put
@Persistent
List<Entity2> items;

Save Entity1 and regenerate the Endpoints class. I believe it should show up.

The Endpoints class is generated with the usual method: list, get, insert, update, remove. Nothing else. But theoretically, calling the list method i would get the entire Entity with all the fields, but they don’t show up :-(

Sorry for frustrating you, but i tried to build more than one simple projects, but the problem still remain. I supposed was the incompatibility with @Unowned TAG , but it wasn’t. It still not work. :-( Any other suggestion? Thank you so much in advance

Hi Stefano – I am not sure what the problem could be here. At a high level it looks like some mismatch between using JDO Annotations and how it is being addressed while generating/executing the cloud endpoints code. I am sorry – but I don’t have any specific solution or alternatives at this point. If you find the solution, please do share.

I don’t think i’m doing wrong because i followed also your fantastic tutorials and the only thing i’ve added in my code is the relationship with an other Entity. If and only if you want and have some “spare time” i can upload my project with or without the auto-generted Endpoint and you could check by yourself if something is wrong. Let me know rominirani ;-) and thank you so much for support.

Hi Stefano – please upload your simplified project code to a url, where I can download from. I am very much interested in understanding what is happening in your scenario. You can email me the link to r o m i n DOT k DOT i r a n i AT GMAIL.COM

Dear Romin,
I have a quick question regarding the API explorer. In your example, while testing API for “insertQuote” I see that you have a request body to fill in but for my case the request body is empty. This is making me unable to test the API. Any idea what is missing here?

First of all, thanks a lot for your website ! It’s a bit my bible about Google Cloud Endpoints.
I have a problem with two entities, Parent and Child. I am just beginning to develop on android and App Engine, and I dont know where I can find informations about relashionships between Parent and Child entitie… I read that (https://developers.google.com/appengine/docs/java/datastore/jdo/relationships) but I can’t get an attribute of my parent entitie from my child entitie…
Did you have by chance, another example website of relationships between Parent and Child entities ? :-)

Thank you for your quick response and your helpful links.
We can use objectify library from Android App ? How ? Because when you generate your cloud endpoint class, I don’t know if it is compatible with Objectify…

I use Objectify with GAE servlet, but with endpoints like android… What do you think about that ?

1. Objectify is for GAE, so it is for use on the Server side. I thought you were mentioning about persisting the data on the server, hence I recommended that.
2. The Cloud Endpoint class that is generated does not generate Objectify code for you. Hence you will have to put that code yourself into the Java class and annotate the same with Endpoint Java annotations to make it an Endpoint class.

{
“error”: {
“message”: “javax.jdo.JDOFatalUserException: A property named javax.jdo.PersistenceManagerFactoryClass must be specified, or a jar file with a META-INF/services/javax.jdo.PersistenceManagerFactory entry must be in the classpath, or a property named javax.jdo.option.PersistenceUnitName must be specified.”,
“code”: 503,
“errors”: [
{
“domain”: “global”,
“reason”: “backendError”,
“message”: “javax.jdo.JDOFatalUserException: A property named javax.jdo.PersistenceManagerFactoryClass must be specified, or a jar file with a META-INF/services/javax.jdo.PersistenceManagerFactory entry must be in the classpath, or a property named javax.jdo.option.PersistenceUnitName must be specified.”
}
]
}
}

Hi Rominirani, Thank you very much for this awesome write up. I’m very new to Cloud endpoints and GAE. A quick question. How do I convert this api backend to run on my google account’s project URL instead of localhost:8888. I believe I need to include my project ID or Web Client ID somewhere. Please clarify. Thanks.

You will need to deploy your app to App Engine. The steps are signing up for App Engine, create a project there first, which will give you the Project ID. Then this project ID is to be placed in the appengine-web.xml file present in the WEB-INF folder. Once done, deploy your project from the IDE or command line.

Hi Rominirani, Thank you for this great tutorials. It helps me a lot!!!

A quick question. I keep getting error when i try insert method.

503 Service Unavailable

– Show headers –

{
“error”: {
“message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”,
“code”: 503,
“errors”: [
{
“domain”: “global”,
“reason”: “backendError”,
“message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”com.inb348.restfultest.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”
}
]
}
}

There is something going wrong with the DataNucleus Enhancer plugin in your Eclipse setup. When the project is built, Eclipse invokes the DataNucleus plugin to enhance your classes that have got annotated with the JDO/JPA annotations. Ideally, you should see a message in your Eclipse console that the Enhancer ran successfully and the the enhanced classes have been generated. Try cleaning the project and/or refer to some forums for this problem. I can’t specifically pin point what could be the root cause.

Sure. You will need to generate your ID otherwise you will get this error since a unique identifier is needed before you can persist the same. One option would be to modify the Persistence code such that if you do not pass one, you can autogenerate one on your one. So you can do a setXXX on the ID before you persist the object.

Thanks a lot for this tutorial.
I am trying to add a new ApiMethod for listing all the entities filtered by a property value.
I created the method and added query.setFilter(), query.setOrdering() methods to extract only the required entities.

Now the challenge is, I get an error symbol in the project folder. I could not see any errors in any of the sub folders and the java files.

i have mailed you the screenshot showing the error and the modified QuoteEndpoint.java file.

Could you please advise me to overcome this issue? If you need further information please ask.

I have found it really useful. I am having the same problems as Reo Lee with my DataNucleus plugin. I get this same error message. Is this a problem with GWT? Or can the endpoint be used with GWT? If so I am not sure how to adjust the change the class path to fix this? Any ideas. Thanks very much

“message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”,
“code”: 503,
“errors”: [
{
“domain”: “global”,
“reason”: “backendError”,
“message”: “org.datanucleus.api.jdo.exceptions.ClassNotPersistenceCapableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.\nNestedThrowables:\norg.datanucleus.exceptions.ClassNotPersistableException: The class \”exampleProjecttext.testpackege.client.Patient\” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”
}
]
}
}

I am not too sure about GWT since I have never used it. However, one thing you can do is to make sure that the sample project, you simply deselect GWT while generating the project from scratch.

Having said that, I think it could be something with your settings or environment. Do take a look at Stack Overflow and other sites, the problem seems to be there for some users. I am sorry – I cannot be of more help here.

Thanks very much for the reply. I have given up on the GWT idea as that just is not working at all… However, I now tried to create a new GAE web application and as soon as it is created the datanucleus build gives errors. Is there a way to refresh the whole system to start from scratch? I have absolutely no clue what half of the forums are referring to (hence why your tutorial was so BRILLIANT! It was understandable :) ).

I am just getting more of the class has not been enhanced errors. In terms of environments what should I be looking for? I have tried to delete eclipse and re-install the GAE plugin but that did nothing. Thanks very much again for your help.

Thank you for this article. However I’m having some issues, I’m using Windows 8 with Eclipse Luna and when I try to run the app locally after annotating and generating the endpoint class, the console says “The class “com.example.myapiproject2.Quote” is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.”

Something has gone wrong with your Project, linking of the JDO libraries and some Eclipse settings for preprocessing of JDO Annotations. Try it in a fresh project. There are some links on Stack Overflow that cover this issue and I suggest looking there.

This article is great, thanks.
I was wondering, is it possible to add Objectify annotations in the entity before creating the Endpoint class?
I would like to use @Cache to enable the use of Memcache with the Datastore.

I haven’t particularly tried it but here is what I would suggest.
a) If you want to use Objectify, you definitely can and stick to its APIs for doing CRUD Operations. This has nothing to do with Cloud Endpoints.
b) Now, write your Cloud Endpoints layer on your own. So in other words, you don’t generate the persistence code from the Endpoint generator. Just write your Endpoints layer and put the code inside that references your Objectify layer.

Thank you rominirani for this explanation. I don’t understand why but after doing this:
1)Create an web application project
2)create and annotate an entity
3)generate endpoint class
4)create a project on the google console and report the app id on the appengine-web.xml
5)deploy

I get 404 not found errors whereas it works perfectly on my local post. Eclipse keeps on saying the deployment was successful as well as the google console. Can you tell me if there is some step that I’m missing?

Since you are saying that the Application deployed successfully, please check the following:

1) Did the Endpoints get deployed correctly. Check out this tip that I had provided in another blog post:

2) Are you receiving the Endpoint Error when you are trying to access the API Explorer on your deployed application. For e.g. http://.appspot.com/_ah/api/explorer ? Are you sure there is no typo or something ?

The favicon message is fine. It is just a while that is not available and does not matter.

I am bit confused why you are able to see the things work locally and not seeing it in the live app engine instance ? It is stupid of me to ask but I am assuming that you are connected to the internet since it does hit the internet for evaluating your API i.e. the API Explorer.

I am currently not having a clue but try maybe another app id, redeploy fresh into that ?

Gerard – Thank you for your feedback and comments. Coming to your points:

1) I do not think that Cloud Endpoints requires an ID. You can design the interface / methods / parameters your own way.
2) If you do plan to generate an ID – then you can do that easily at the Server side itself before insertion or if you are depending on App Engine to do it. That is fine too.
2) If you plan to make the caller give you the ID – then you will need to provide that as one of the parameters. But then you will need to do your own check to ensure that it is not a duplicate ID or something like that.

Great tutorial! I’m just making an App Engine application in a universty project and I’m a stucked.
I prefer IntelliJ IDEA as Eclipse. Is there any way to generate the Endpoints class in IntelliJ? I’ve googled it and tried everíthing but I couldn’t find anything.

I believe the Google plugins are updated and available for Eclipse. I don’t think they do that for IntelliJ. Having said that, there might some stuff available from IntelliJ but I have never ventured into that IDE for App Engine development. I do believe that they have support for developing App Engine apps (maybe a paid version) but what the current state of support is for Cloud Endpoints in that is something that I am not aware of.