Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Google Cloud Endpoints: Building Third-Party AP...

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

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.

Avatar for Roman Kirillov

Roman Kirillov

July 10, 2013
Tweet

More Decks by Roman Kirillov

Other Decks in Technology

Transcript

  1. Google Cloud Endpoints Third-party APIs on Google AppEngine Roman "sgzmd"

    Kirillov - Google Developing on the Google Cloud Platform with Java - 2013-07-10
  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. 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. 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. REST API example (really primitive one) Say, we have a

    book: We want to: #GoogleCloudPlatform { " n a m e " : " T h e H i t c h h i k e r ' s G u i d e t o t h e G a l a x y " } J S O N Add it to the book collection Retrieve it from there · · 6/39
  6. REST API example Adding new data #GoogleCloudPlatform c u r

    l - d " { ' n a m e ' : ' T h e H i t c h h i k e r \ ' s G u i d e t o t h e G a l a x y ' } " \ h t t p s : / / s a m p l e - r e s t f u l - a p i . a p p s p o t . c o m / _ a h / a p i / b o o k e n d p o i n t / v 1 / b o o k \ - X P O S T \ - H " A c c e p t : a p p l i c a t i o n / j s o n " \ - H " C o n t e n t - t y p e : a p p l i c a t i o n / j s o n " { " k e y " : { " k i n d " : " B o o k " , " i d " : " 4 2 " , } , " n a m e " : " T h e H i t c h h i k e r ' s G u i d e t o t h e G a l a x y " , } Sending data to the URL using HTTP POST Request and response are in JSON · · 7/39
  7. REST API example Listing the data Note: / b o

    o k e n d p o i n t / v 1 / b o o k is 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 / b o o k e n d p o i n t / v 1 / b o o k / 4 2 #GoogleCloudPlatform c u r l h t t p s : / / s a m p l e - r e s t f u l - a p i . a p p s p o t . c o m / _ a h / a p i / b o o k e n d p o i n t / v 1 / b o o k \ - X G E T - H " A c c e p t : a p p l i c a t i o n / j s o n " { " i t e m s " : [ { " k e y " : { " k i n d " : " B o o k " , " i d " : " 4 2 " , } , " n a m e " : " T h e H i t c h h i k e r ' s G u i d e t o t h e G a l a x y " , } , ] , } 8/39
  8. UI mocks What do we want to get in the

    end #GoogleCloudPlatform 10/39
  9. 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
  10. 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
  11. Data model Defining data object for Sensor #GoogleCloudPlatform @ P

    e r s i s t e n c e C a p a b l e ( i d e n t i t y T y p e = I d e n t i t y T y p e . A P P L I C A T I O N ) p u b l i c c l a s s S e n s o r { @ P r i m a r y K e y @ P e r s i s t e n t ( v a l u e S t r a t e g y = I d G e n e r a t o r S t r a t e g y . I D E N T I T Y ) p r i v a t e K e y k e y ; / / U n i q u e l y i d e n t i f i e s s e n s o r i n h o m e n e t w o r k @ P e r s i s t e n t @ U n i q u e p r i v a t e S t r i n g n e t w o r k I d ; / / S e n s o r ' s d a t a i s b e i n g u s e d @ P e r s i s t e n t p r i v a t e B o o l e a n a c t i v e ; / / L a s t t i m e s e n s o r f i r e d @ P e r s i s t e n t p r i v a t e L o n g l a s t A c t i v e = 0 L ; / / M o t i o n , t e m p e r a t u r e , e t c . @ P e r s i s t e n t p r i v a t e S e n s o r T y p e s e n s o r T y p e ; } J A V A 13/39
  12. Data model Defining data object for Room ...and this is

    pretty much it for the data. #GoogleCloudPlatform @ P e r s i s t e n c e C a p a b l e ( i d e n t i t y T y p e = I d e n t i t y T y p e . A P P L I C A T I O N ) p u b l i c c l a s s R o o m { p r i v a t e s t a t i c f i n a l I n s t a n t N E V E R = n e w I n s t a n t ( 0 ) ; @ P r i m a r y K e y @ P e r s i s t e n t ( v a l u e S t r a t e g y = I d G e n e r a t o r S t r a t e g y . I D E N T I T Y ) p r i v a t e K e y k e y ; @ P e r s i s t e n t p r i v a t e S t r i n g n a m e ; @ P e r s i s t e n t @ E l e m e n t ( d e p e n d e n t = " t r u e " ) p r i v a t e L i s t < S e n s o r > s e n s o r s ; } J A V A 14/39
  13. API interface Think of this as (almost) pseudocode #GoogleCloudPlatform c

    l a s s A p i B a c k e n d { L i s t < R o o m > l i s t R o o m s ( ) { } R o o m a d d R o o m ( R o o m r o o m ) { } v o i d d e l e t e R o o m ( R o o m I d r o o m I d ) { } R o o m u p d a t e R o o m ( R o o m I d r o o m I d , R o o m r o o m ) { } R o o m a d d S e n s o r ( R o o m I d r o o m I d , S e n s o r s e n s o r ) { } v o i d s e n s o r U p d a t e d ( S e n s o r N e t w o r k I d n e t w o r k I d ) { } v o i d a r m ( R o o m I d r o o m I d ) { } v o i d d i s a r m ( R o o m I d r o o m I d ) { } v o i d a r m ( ) { } v o i d d i s a r m ( ) { } } J A V A 16/39
  14. 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 p u b l i c R o o m u p d a t e R o o m ( N a m e d ( " r o o m " ) L o n g r o o m I d , R o o m u p d a t e d R o o m ) { P e r s i s t e n c e M a n a g e r p m = g e t P M ( ) ; t r y { R o o m r o o m = ( R o o m ) p m . g e t O b j e c t B y I d ( R o o m . c l a s s , r o o m I d ) ; r o o m . u p d a t e F r o m ( u p d a t e d R o o m ) ; r e t u r n r o o m ; } f i n a l l y { p m . c l o s e ( ) ; } } J A V A 17/39
  15. Adding API annotations Converting AppEngine backend to REST web service

    And this is pretty much it for API implementation. #GoogleCloudPlatform @ A p i M e t h o d ( n a m e = " u p d a t e R o o m " , h t t p M e t h o d = " P U T " , p a t h = " r o o m s / { r o o m } " ) p u b l i c R o o m u p d a t e R o o m ( @ N a m e d ( " r o o m " ) L o n g r o o m I d , R o o m u p d a t e d R o o m ) { / / . . . } J A V A 18/39
  16. Let's take it for a ride Note: you can do

    the same thing against API running locally. #GoogleCloudPlatform r o m a n $ e x p o r t E N D P O I N T = " h t t p s : / / c l o u d - e n d p o i n t s - e x a m p l e . a p p s p o t . c o m / _ a h / a p i " r o m a n $ c u r l " $ E N D P O I N T / m o n i t o r i n g / v 1 / r o o m s " \ - X P O S T \ - H " A c c e p t : a p p l i c a t i o n / j s o n " \ - H " C o n t e n t - t y p e : a p p l i c a t i o n / j s o n " \ - d " { ' n a m e ' : ' B e d r o o m ' } " { " k e y " : { " k i n d " : " R o o m " , " a p p I d " : " s ~ c l o u d - e n d p o i n t s - e x a m p l e " , " i d " : " 1 0 0 1 " , " c o m p l e t e " : t r u e } , " n a m e " : " B e d r o o m " , } 19/39
  17. Building our first client In HTML code: In JavaScript code:

    #GoogleCloudPlatform Loading Google JavaScript client Initialising your client object Using the API. · · · < s c r i p t s r c = " h t t p s : / / a p i s . g o o g l e . c o m / j s / c l i e n t . j s ? o n l o a d = i n i t " > < / s c r i p t > f u n c t i o n i n i t ( ) { / / c h a n g e t o l o c a l A P I e n d p o i n t f o r l o c a l t e s t i n g v a r R O O T = ' h t t p s : / / c l o u d - e n d p o i n t s - e x a m p l e . a p p s p o t . c o m / _ a h / a p i ' ; g a p i . c l i e n t . l o a d ( ' m o n i t o r i n g ' , ' v 1 ' , r e l o a d A l l D a t a , R O O T ) ; } 20/39
  18. Building a first client Calling the API: adding a new

    room #GoogleCloudPlatform v a r a d d R o o m = f u n c t i o n ( n a m e ) { / / b u i l d i n g J S O N o b j e c t t o b e s e n t t o t h e A P I v a r r o o m = { ' n a m e ' : n a m e } ; / / c a l l i n g t h e A P I g a p i . c l i e n t . m o n i t o r i n g . a d d R o o m ( r o o m ) . e x e c u t e ( f u n c t i o n ( r e s p ) { / / p r o c e s s i n g t h e r e s p o n s e i f ( r e s p ) { r e l o a d A l l D a t a ( t r u e ) ; } } ) ; } ; J A V A S C R I P T 21/39
  19. 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
  20. 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 r o m a n $ ~ / b i n / a p p e n g i n e - j a v a - s d k - 1 . 8 . 0 / b i n / e n d p o i n t s . s h \ g e t - c l i e n t - l i b c o m . s g z m d . e x a m p l e s . c l o u d e n d p o i n t s . A p i B a c k e n d c l o u d - e n d p o i n t s - e x a m p l e - m o n i t o r i n g - v 1 - * - s o u r c e s . j a r * m o n i t o r i n g - v 1 - g e n e r a t e d - s o u r c e / · · 24/39
  21. 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 developers.google.com/appengine/docs/java/endpoints/consume_android 25/39
  22. Creating service object and calling API Service object is your

    interface to the API #GoogleCloudPlatform p u b l i c c l a s s M o n i t o r i n g P r o v i d e r { p r i v a t e s t a t i c f i n a l M o n i t o r i n g M O N I T O R I N G = n e w M o n i t o r i n g ( A n d r o i d H t t p . n e w C o m p a t i b l e T r a n s p o r t ( ) , n e w G s o n F a c t o r y ( ) , n u l l ) ; p u b l i c s t a t i c M o n i t o r i n g g e t ( ) { r e t u r n M O N I T O R I N G ; } } / / s o m e w h e r e i n y o u r a c t i v i t y - c a l l i n g L i s t R o o m s m e t h o d n e w A s y n c T a s k < V o i d , V o i d , L i s t < R o o m > > ( ) { @ O v e r r i d e p r o t e c t e d L i s t < R o o m > d o I n B a c k g r o u n d ( V o i d . . . p a r a m s ) { r e t u r n M o n i t o r i n g P r o v i d e r . g e t ( ) . l i s t R o o m s ( ) . e x e c u t e ( ) . g e t I t e m s ( ) ; } } . e x e c u t e ( ) ; J A V A 26/39
  23. Creating service object and calling API Service object is your

    interface to the API #GoogleCloudPlatform / / ' e n a b l e d ' i s a c h e c k b o x v i e w i n l i s t i t e m e n a b l e d . s e t O n C h e c k e d C h a n g e L i s t e n e r ( n e w O n C h e c k e d C h a n g e L i s t e n e r ( ) { @ O v e r r i d e p u b l i c v o i d o n C h e c k e d C h a n g e d ( C o m p o u n d B u t t o n b u t t o n V i e w , f i n a l b o o l e a n i s C h e c k e d ) { n e w A s y n c T a s k < V o i d , V o i d , V o i d > ( ) { / / n e t w o r k i s p r o h i b i t e d o n U I t h r e a d @ O v e r r i d e p r o t e c t e d V o i d d o I n B a c k g r o u n d ( V o i d . . . p a r a m s ) { t r y { M o n i t o r i n g P r o v i d e r . g e t ( ) / / g e t t i n g i n s t a n c e o f s e r v i c e o b j e c t . a r m ( i s C h e c k e d ) / / c r e a t i n g a r e q u e s t . s e t S e n s o r ( s e n s o r . g e t I d ( ) ) / / s e t t i n g r e q u e s t p a r a m e t e r s . s e t R o o m ( s e n s o r . g e t R o o m I d ( ) ) . e x e c u t e ( ) ; / / e x e c u t i n g t h e r e q u e s t } c a t c h ( I O E x c e p t i o n e ) { / / y o u r p r o b a b l y w o u l d w a n t s o m e b e t t e r e r r o r h a n d l i n g h e r e T h r o w a b l e s . p r o p a g a t e ( e ) ; } } } . e x e c u t e ( ) ; } } ) ; J A V A 27/39
  24. 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
  25. 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
  26. 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.
  27. Backend changes #GoogleCloudPlatform @ A p i ( n a

    m e = " m o n i t o r i n g " , v e r s i o n = " v 2 " , c l i e n t I d s = { " y o u r - a n d r o i d - k e y . g o o g l e u s e r c o n t e n t . c o m " } , a u d i e n c e s = { " y o u r - w e b - k e y . g o o g l e u s e r c o n t e n t . c o m " } ) c l a s s A p i B a c k e n d { / / . . . @ A p i M e t h o d ( n a m e = " l i s t R o o m s " , h t t p M e t h o d = " G E T " , p a t h = " r o o m s " ) p u b l i c L i s t < R o o m > l i s t R o o m s ( U s e r u s e r ) t h r o w s O A u t h R e q u e s t E x c e p t i o n { c h e c k A u t h ( u s e r ) ; / / . . . } p r i v a t e v o i d c h e c k A u t h ( U s e r u s e r ) t h r o w s O A u t h R e q u e s t E x c e p t i o n { i f ( u s e r = = n u l l ) { t h r o w n e w O A u t h R e q u e s t E x c e p t i o n ( " T h i s m e t h o d r e q u i r e s a u t h e n t i c a t i o n " ) ; } } J A V A 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
  28. 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: · · · < u s e s - p e r m i s s i o n a n d r o i d : n a m e = " a n d r o i d . p e r m i s s i o n . G E T _ A C C O U N T S " / > < u s e s - p e r m i s s i o n a n d r o i d : n a m e = " a n d r o i d . p e r m i s s i o n . U S E _ C R E D E N T I A L S " / > 35/39
  29. Modify Android client code Without 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