Como instalar “Aggregate” en un servidor “appengine” de Google.
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
-
Upload
roman-kirillov -
Category
Technology
-
view
4.182 -
download
3
description
Transcript of 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
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
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
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
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
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
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
Better example: home monitoring(part of a real open source project!)
UI mocksWhat do we want to get in the end
#GoogleCloudPlatform 10/39
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
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
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
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
UI mocks
#GoogleCloudPlatform 15/39
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
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
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
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
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
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
Building a first clientcloud-endpoints-js-client.appspot.com – try it yourself.
#GoogleCloudPlatform 22/39
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
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
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
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
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
Better example: home monitoring
#GoogleCloudPlatform 28/39
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
Creating API project in Google API console
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
Configuring new API client
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.
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
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
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
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
<Thank You!>
g+ google.com/+RomanKirillovtwitter @sgzmd
github github.com/sigizmund