Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine


Published on

This is a slide deck of a talk given to a London GDG meeting on 2013/07/10. It covers following topics:

* Building RESTful APIs using Cloud Endpoints and Google AppEngine
* Building Javascript and Android clients for these APIs
* Enabling OAuth2 authentication for this APIs.

Full video recording of the talk will be available later.

Published in: Technology, Education
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine

  1. 1. Google Cloud Endpoints Third-partyAPIson GoogleAppEngine Roman "sgzmd" Kirillov - Google Developing on the Google Cloud Platform with Java - 2013-07-10
  2. 2. Hello World Some introductions are in order #GoogleCloudPlatform If you have a question, raise a hand. There will be dedicated Q&A time at the end of the lecture All source code will be provided in the form of a GitHub link · · · 3/39
  3. 3. Today's plan Does everyone know what a RESTful web API is? #GoogleCloudPlatform A little bit of theory. Why another solution for APIs? Building an API on AppEngine: what does it take? Building a simple client for our API · · · 4/39
  4. 4. What are RESTful APIs (quick recap) #GoogleCloudPlatform A web service, which uses HTTP as a transport Central idea: there are resources which we want to export Resources are sent back and forth using their representation REST = representational state transfer Four main operations, mapped to HTTP methods: · · · · · GET – read or list the data POST – add new data PUT – update existing data DELETE – as follows from the name · · · · See also: wiki:Representation State Transfer 5/39
  5. 5. REST API example (really primitive one) Say, we have a book: We want to: #GoogleCloudPlatform { "name": "TheHitchhiker'sGuidetotheGalaxy" } JSON Add it to the book collection Retrieve it from there · · 6/39
  6. 6. REST API example Adding new data #GoogleCloudPlatform curl -d "{'name': 'The Hitchhiker's Guide to the Galaxy'}" -X POST -H "Accept: application/json" -H "Content-type: application/json" { "key": { "kind": "Book", "id": "42", }, "name": "The Hitchhiker's Guide to the Galaxy", } Sending data to the URL using HTTP POST Request and response are in JSON · · 7/39
  7. 7. REST API example Listing the data Note: /bookendpoint/v1/bookis a collection URL and can be used to list the data. If we want to read the data about specific book, we would use Element URL, like /bookendpoint/v1/book/42 #GoogleCloudPlatform curl -X GET -H "Accept: application/json" { "items": [ { "key": { "kind": "Book", "id": "42", }, "name": "The Hitchhiker's Guide to the Galaxy", }, ], } 8/39
  8. 8. Better example: home monitoring (part of a real open source project!)
  9. 9. UI mocks What do we want to get in the end #GoogleCloudPlatform 10/39
  10. 10. Implementation outline How do we get there #GoogleCloudPlatform Defining and implementing a model of our application Defining an interface of the API Implementing API endpoint Generating client libraries Implementing a client in JS Implementing an Android client · · · · · · 11/39
  11. 11. Application data model #GoogleCloudPlatform We will define a POJO and spice it up with some JDO Using JDO isn't mandatory – there are other options available JDO is closest to what you see in AppEngine for Python · · · 12/39
  12. 12. Data model Defining data object for Sensor #GoogleCloudPlatform @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Sensor { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; // Uniquely identifies sensor in home network @Persistent @Unique private String networkId; // Sensor's data is being used @Persistent private Boolean active; // Last time sensor fired @Persistent private Long lastActive = 0L; // Motion, temperature, etc. @Persistent private SensorType sensorType; } JAVA 13/39
  13. 13. Data model Defining data object for Room ...and this is pretty much it for the data. #GoogleCloudPlatform @PersistenceCapable(identityType = IdentityType.APPLICATION) public class Room { private static final Instant NEVER = new Instant(0); @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; @Persistent private String name; @Persistent @Element(dependent = "true") private List<Sensor> sensors; } JAVA 14/39
  14. 14. UI mocks #GoogleCloudPlatform 15/39
  15. 15. API interface Think of this as (almost) pseudocode #GoogleCloudPlatform classApiBackend{ List<Room>listRooms(){} RoomaddRoom(Roomroom){} voiddeleteRoom(RoomIdroomId){} RoomupdateRoom(RoomIdroomId,Roomroom){} RoomaddSensor(RoomIdroomId,Sensorsensor){} voidsensorUpdated(SensorNetworkIdnetworkId){} voidarm(RoomIdroomId){} voiddisarm(RoomIdroomId){} voidarm(){} voiddisarm(){} } JAVA 16/39
  16. 16. API implementation Code for API will look much like any other Java code using JDO. In fact, you can use your existing backend code. #GoogleCloudPlatform publicRoomupdateRoom( Named("room")LongroomId,RoomupdatedRoom){ PersistenceManagerpm=getPM(); try{ Roomroom=(Room)pm.getObjectById( Room.class,roomId); room.updateFrom(updatedRoom); returnroom; }finally{ pm.close(); } } JAVA 17/39
  17. 17. Adding API annotations Converting AppEngine backend to REST web service And this is pretty much it for API implementation. #GoogleCloudPlatform @ApiMethod( name="updateRoom", httpMethod="PUT", path="rooms/{room}") publicRoomupdateRoom( @Named("room")LongroomId, RoomupdatedRoom){ //... } JAVA 18/39
  18. 18. Let's take it for a ride Note: you can do the same thing against API running locally. #GoogleCloudPlatform roman $ export ENDPOINT="" roman $ curl "$ENDPOINT/monitoring/v1/rooms" -X POST -H "Accept: application/json" -H "Content-type: application/json" -d "{'name': 'Bedroom'}" { "key": { "kind": "Room", "appId": "s~cloud-endpoints-example", "id": "1001", "complete": true }, "name": "Bedroom", } 19/39
  19. 19. Building our first client In HTML code: In JavaScript code: #GoogleCloudPlatform Loading Google JavaScript client Initialising your client object Using the API. · · · <script src=""></script> function init() { // change to local API endpoint for local testing var ROOT = ''; gapi.client.load('monitoring', 'v1', reloadAllData, ROOT); } 20/39
  20. 20. Building a first client Calling the API: adding a new room #GoogleCloudPlatform varaddRoom=function(name){ //buildingJSONobjecttobesenttotheAPI varroom={ 'name':name }; //callingtheAPI gapi.client.monitoring.addRoom(room).execute(function(resp){ //processingtheresponse if(resp){ reloadAllData(true); } }); }; JAVASCRIPT 21/39
  21. 21. Building a first client – try it yourself. #GoogleCloudPlatform 22/39
  22. 22. Stepping it up: Android client A bit more fiddly than JavaScript client. In this section: #GoogleCloudPlatform Generating an Android client library Adding a whole bunch of jars to your project Creating a service object Calling the API · · · · 23/39
  23. 23. Generating Android client library From your project's WEB-INF directory, do: You mostly care about this generated stuff: Copy *jar* to your project's 'libs', and link to generated source. #GoogleCloudPlatform roman$~/bin/appengine-java-sdk-1.8.0/bin/ get-client-libcom.sgzmd.examples.cloudendpoints.ApiBackend cloud-endpoints-example-monitoring-v1-*-sources.jar* monitoring-v1-generated-source/ · · 24/39
  24. 24. Adding jars to Android project From 'libs' subdirectory of the generated client, copy: #GoogleCloudPlatform google-api-client-1.12.0-beta.jar google-api-client-android-1.12.0-beta.jar google-http-client-1.12.0-beta.jar google-http-client-android-1.12.0-beta.jar google-http-client-gson-1.12.0-beta.jar google-oauth-client-1.12.0-beta.jar gson-2.1.jar guava-jdk5-13.0.jar jsr305-1.3.9.jar · · · · · · · · · Check 25/39
  25. 25. Creating service object and calling API Service object is your interface to the API #GoogleCloudPlatform public class MonitoringProvider { private static final Monitoring MONITORING = new Monitoring( AndroidHttp.newCompatibleTransport(), new GsonFactory(), null); public static Monitoring get() { return MONITORING; } } // somewhere in your activity - calling ListRooms method new AsyncTask<Void, Void, List<Room>>() { @Override protected List<Room> doInBackground(Void... params) { return MonitoringProvider.get().listRooms().execute().getItems(); } }.execute(); JAVA 26/39
  26. 26. Creating service object and calling API Service object is your interface to the API #GoogleCloudPlatform // 'enabled' is a checkbox view in list item enabled.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged( CompoundButton buttonView, final boolean isChecked) { new AsyncTask<Void, Void, Void>() { // network is prohibited on UI thread @Override protected Void doInBackground(Void... params) { try { MonitoringProvider.get() // getting instance of service object .arm(isChecked) // creating a request .setSensor(sensor.getId()) // setting request parameters .setRoom(sensor.getRoomId()) .execute(); // executing the request } catch (IOException e) { // your probably would want some better error handling here Throwables.propagate(e); } } }.execute(); } }); JAVA 27/39
  27. 27. Better example: home monitoring #GoogleCloudPlatform 28/39
  28. 28. Staying safe: authentication (do we still have any time left?) #GoogleCloudPlatform Creating an API project and application keys Modifying backend code to use authentication Preparing your Android project to use authentication Modifying Android code Will involve few steps, can be somewhat fiddly, but ultimately is fairly straightforward. · · · · 29/39
  29. 29. Creating API project in Google API console
  30. 30. Configuring new API client "Create an OAuth 2.0 client ID..." #GoogleCloudPlatform New Client configuration Installed Application Android Use same SHA1 you currently use to sign your Android apps. Debug key will work, too. You will also need a Web app key. Use localhost if you don't have a real web app. · · · · · 31/39
  31. 31. Configuring new API client
  32. 32. Configuring new API client Final result should look like that: You'll need both keys for Android app to work, but it's OK to re-use your normal web application key for that purpose.
  33. 33. Backend changes #GoogleCloudPlatform @Api( name = "monitoring", version = "v2", clientIds = {""}, audiences = {""}) class ApiBackend { // ... @ApiMethod(name = "listRooms", httpMethod = "GET", path = "rooms") public List<Room> listRooms(User user) throws OAuthRequestException { checkAuth(user); // ... } private void checkAuth(User user) throws OAuthRequestException { if (user == null) { throw new OAuthRequestException("This method requires authentication"); } } JAVA Updating @Api annotation for your API class. Note, that I use version v2 which can co-exist with v1 in the same application. Adding an extra parameter to every method to be auth protected · · 34/39
  34. 34. Updating Android project Optional step if running on Android emulator: make sure your Android Target is created using Google APIs AVD and not just plain Android. Note: due to variety of Android devices, it is always a good idea not to assume that Google Play services are present on the device and check it at runtime. #GoogleCloudPlatform Ensure you have Google Play services installed in SDK Manager Copy google-play-services.jar to libs directory of your project Add following two lines to your AndroidManifest.xml: · · · <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" /> 35/39
  35. 35. Modify Android client code Without going into too many details ... Look through – it's mostly about Auth. #GoogleCloudPlatform Verify Google Play Services are present on the device Create GoogleAccountCredential using your web app key Start Account Picker Intent to choose an account In onActivityResult save it to Shared Preferences Update created Credential with the account name Use it to construct your service object · · · · · · 36/39
  36. 36. Code, docs and links #GoogleCloudPlatform · · · 37/39
  37. 37. <Thank You!> g+ twitter @sgzmd github