google cloud endpoints: building third-party apis on google appengine

39

Upload: roman-kirillov

Post on 22-May-2015

4.180 views

Category:

Technology


3 download

DESCRIPTION

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.

TRANSCRIPT

Page 1: Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Page 2: Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine

Google Cloud EndpointsThird-party APIs on Google AppEngine

Roman "sgzmd" Kirillov - GoogleDeveloping on the Google Cloud Platform with Java - 2013-07-10

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

Hello WorldSome 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

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

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

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

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

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

REST API example(really primitive one)

Say, we have a book:

We want to:

#GoogleCloudPlatform

{ "name": "The Hitchhiker's Guide to the Galaxy"}

JSON

Add it to the book collection

Retrieve it from there

·

·

6/39

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

REST API exampleAdding new data

#GoogleCloudPlatform

curl -d "{'name': 'The Hitchhiker\'s Guide to the Galaxy'}" \ https://sample-restful-api.appspot.com/_ah/api/bookendpoint/v1/book \ -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

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

REST API exampleListing the data

Note: /bookendpoint/v1/book is a collection URL and can be used to list the data. If we want toread the data about specific book, we would use Element URL, like /bookendpoint/v1/book/42

#GoogleCloudPlatform

curl https://sample-restful-api.appspot.com/_ah/api/bookendpoint/v1/book \ -X GET -H "Accept: application/json"

{ "items": [ { "key": { "kind": "Book", "id": "42", }, "name": "The Hitchhiker's Guide to the Galaxy", }, ],}

8/39

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

Better example: home monitoring(part of a real open source project!)

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

UI mocksWhat do we want to get in the end

#GoogleCloudPlatform 10/39

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

Implementation outlineHow 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

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

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

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

Data modelDefining 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

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

Data modelDefining 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

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

UI mocks

#GoogleCloudPlatform 15/39

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

API interfaceThink of this as (almost) pseudocode

#GoogleCloudPlatform

class ApiBackend { List<Room> listRooms() {} Room addRoom(Room room) {} void deleteRoom(RoomId roomId) {} Room updateRoom(RoomId roomId, Room room) {} Room addSensor(RoomId roomId, Sensor sensor) {} void sensorUpdated(SensorNetworkId networkId) {} void arm(RoomId roomId) {} void disarm(RoomId roomId) {} void arm() {} void disarm() {}}

JAVA

16/39

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

API implementationCode for API will look much like any other Java code using JDO. In fact, youcan use your existing backend code.

#GoogleCloudPlatform

public Room updateRoom( Named("room") Long roomId, Room updatedRoom) {

PersistenceManager pm = getPM(); try { Room room = (Room) pm.getObjectById( Room.class, roomId); room.updateFrom(updatedRoom); return room; } finally { pm.close(); }}

JAVA

17/39

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

Adding API annotationsConverting AppEngine backend to REST web service

And this is pretty much it for API implementation.

#GoogleCloudPlatform

@ApiMethod( name = "updateRoom", httpMethod = "PUT", path = "rooms/{room}")public Room updateRoom( @Named("room") Long roomId, Room updatedRoom) { // ...}

JAVA

18/39

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

Let's take it for a ride

Note: you can do the same thing against API running locally.

#GoogleCloudPlatform

roman $ export ENDPOINT="https://cloud-endpoints-example.appspot.com/_ah/api"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

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

Building our first client

In HTML code:

In JavaScript code:

#GoogleCloudPlatform

Loading Google JavaScript client

Initialising your client object

Using the API.

·

·

·

<script src="https://apis.google.com/js/client.js?onload=init"></script>

function init() { // change to local API endpoint for local testing var ROOT = 'https://cloud-endpoints-example.appspot.com/_ah/api'; gapi.client.load('monitoring', 'v1', reloadAllData, ROOT);}

20/39

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

Building a first clientCalling the API: adding a new room

#GoogleCloudPlatform

var addRoom = function(name) { // building JSON object to be sent to the API var room = { 'name': name };

// calling the API gapi.client.monitoring.addRoom(room).execute(function(resp){ // processing the response if (resp) { reloadAllData(true); } });};

JAVASCRIPT

21/39

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

Building a first clientcloud-endpoints-js-client.appspot.com – try it yourself.

#GoogleCloudPlatform 22/39

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

Stepping it up: Android clientA 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

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

Generating Android client libraryFrom 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/endpoints.sh \ get-client-lib com.sgzmd.examples.cloudendpoints.ApiBackend

cloud-endpoints-example-monitoring-v1-*-sources.jar*

monitoring-v1-generated-source/

·

·

24/39

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

Adding jars to Android projectFrom '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 developers.google.com/appengine/docs/java/endpoints/consume_android

25/39

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

Creating service object and calling APIService 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 methodnew AsyncTask<Void, Void, List<Room>>() { @Override protected List<Room> doInBackground(Void... params) { return MonitoringProvider.get().listRooms().execute().getItems(); }}.execute();

JAVA

26/39

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

Creating service object and calling APIService object is your interface to the API

#GoogleCloudPlatform

// 'enabled' is a checkbox view in list itemenabled.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

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

Better example: home monitoring

#GoogleCloudPlatform 28/39

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

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 fairlystraightforward.

·

·

·

·

29/39

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

Creating API project in Google API console

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

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 keywill work, too.

You will also need a Web app key. Use localhost if you don't have a realweb app.

·

·

·

·

·

31/39

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

Configuring new API client

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

Configuring new API clientFinal result should look like that:

You'll need both keys for Android app to work, but it's OK to re-use yournormal web application key for that purpose.

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

Backend changes

#GoogleCloudPlatform

@Api( name = "monitoring", version = "v2", clientIds = {"your-android-key.googleusercontent.com"}, audiences = {"your-web-key.googleusercontent.com"})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 v1in the same application.

Adding an extra parameter to every method to be auth protected

·

·

34/39

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

Updating Android project

Optional step if running on Android emulator: make sure your Android Target is created usingGoogle 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 Playservices 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

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

Modify Android client codeWithout going into too many details ...

Look through RoomListActivity.java – 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

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

Code, docs and links

#GoogleCloudPlatform

github.com/sigizmund/cloud-endpoints-java-sample

cloud-endpoints-js-client.appspot.com

developers.google.com/appengine/docs/java/endpoints

·

·

·

37/39

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

<Thank You!>

g+ google.com/+RomanKirillovtwitter @sgzmd

github github.com/sigizmund

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