Writing the API: A Simple GET
In this part of the tutorial, you'll create a backend API with methods serving two different GET requests:
- A GET request that returns a list of all the hardcoded Greeting objects.
- A GET request that includes the integer 0 or 1 in the path to specify a particular greeting.
Coding a backend with a simple GET method
To write a simple backend:
-
Create a new folder named
helloendpoints
(the folder name is unimportant). -
Inside the folder, create a file named
app.yaml
and add the following contents:application: your-app-id version: 1 runtime: python27 threadsafe: true api_version: 1 handlers: # Endpoints handler - url: /_ah/spi/.* script: helloworld_api.APPLICATION libraries: - name: pycrypto version: latest - name: endpoints version: 1.0
Replace
your-app-id
with with the project ID you obtained when you created the App Engine project . -
Inside the same folder, create a file named
helloworld_api.py
, and add the following imports:"""Hello World API implemented using Google Cloud Endpoints. Defined here are the ProtoRPC messages needed to define Schemas for methods as well as those methods defined in an API. """ import endpoints from protorpc import messages from protorpc import message_types from protorpc import remote
All of the imports shown are required for an Endpoints API backend.
-
Add the message classes to be used in the requests and responses:
package = 'Hello' class Greeting(messages.Message): """Greeting that stores a message.""" message = messages.StringField(1) class GreetingCollection(messages.Message): """Collection of Greetings.""" items = messages.MessageField(Greeting, 1, repeated=True) STORED_GREETINGS = GreetingCollection(items=[ Greeting(message='hello world!'), Greeting(message='goodbye world!'), ])
Notice that we are hardcoding the message content to be returned, to keep things simple.
Also, notice the
package=
line. This is used by the underlying ProtoRpc when creating names for the ProtoRPC messages you create. This package name will show up as a prefix to your message class names in the discovery doc and client libraries. -
Add the API code itself: we are adding an API named
helloworld
that has two methods serving GET requests, one that returns all Greetings and one that returns only the specified greeting:@endpoints.api(name='helloworld', version='v1') class HelloWorldApi(remote.Service): """Helloworld API v1.""" @endpoints.method(message_types.VoidMessage, GreetingCollection, path='hellogreeting', http_method='GET', name='greetings.listGreeting') def greetings_list(self, unused_request): return STORED_GREETINGS ID_RESOURCE = endpoints.ResourceContainer( message_types.VoidMessage, id=messages.IntegerField(1, variant=messages.Variant.INT32)) @endpoints.method(ID_RESOURCE, Greeting, path='hellogreeting/{id}', http_method='GET', name='greetings.getGreeting') def greeting_get(self, request): try: return STORED_GREETINGS.items[request.id] except (IndexError, TypeError): raise endpoints.NotFoundException('Greeting %s not found.' % (request.id,))
-
Finally, add the API server code:
APPLICATION = endpoints.api_server([HelloWorldApi])
-
When you are finished, your file should look like this:
"""Hello World API implemented using Google Cloud Endpoints. Defined here are the ProtoRPC messages needed to define Schemas for methods as well as those methods defined in an API. """ import endpoints from protorpc import messages from protorpc import message_types from protorpc import remote package = 'Hello' class Greeting(messages.Message): """Greeting that stores a message.""" message = messages.StringField(1) class GreetingCollection(messages.Message): """Collection of Greetings.""" items = messages.MessageField(Greeting, 1, repeated=True) STORED_GREETINGS = GreetingCollection(items=[ Greeting(message='hello world!'), Greeting(message='goodbye world!'), ]) @endpoints.api(name='helloworld', version='v1') class HelloWorldApi(remote.Service): """Helloworld API v1.""" @endpoints.method(message_types.VoidMessage, GreetingCollection, path='hellogreeting', http_method='GET', name='greetings.listGreeting') def greetings_list(self, unused_request): return STORED_GREETINGS ID_RESOURCE = endpoints.ResourceContainer( message_types.VoidMessage, id=messages.IntegerField(1, variant=messages.Variant.INT32)) @endpoints.method(ID_RESOURCE, Greeting, path='hellogreeting/{id}', http_method='GET', name='greetings.getGreeting') def greeting_get(self, request): try: return STORED_GREETINGS.items[request.id] except (IndexError, TypeError): raise endpoints.NotFoundException('Greeting %s not found.' % (request.id,)) APPLICATION = endpoints.api_server([HelloWorldApi])
Running and testing your backend API
To run and test the backend you just created:
-
Change to the
helloworld
parent directory and start the API in the development server by invoking:google_appengine/dev_appserver.py helloendpoints
When the backend is running successfully, a message similar to this one is displayed:
INFO 2013-10-07 19:41:16,687 admin_server.py:117] Starting admin server at: http://localhost:8000
-
In your browser, visit this URL:
http://localhost:8080/_ah/api/explorer
This opens up the API Explorer for your backend. Notice the list of APIs displayed with helloworld API in that list.
-
Click helloworld to display the available methods. Click helloworld.greetings.getGreetings to display the Explorer form for it:
-
Our simple backend has two "canned" messages in an array. Get the first message by entering a value of
0
in the Id text box, then click Execute. -
Notice the display of the request and response. In the Response, you'll see the OK result and the returned message, hello world! .
-
Enter a value of
1
in the Id text box, then click Execute ; this time the message is goodbye world !.
Code summary
The Greeting message class is defined for the requests coming into the
greetings.getGreeting
and
greetings.listGreeting
methods and the responses
returned by them. A
message class
performs a mapping function so the incoming data can be extracted and supplied
to the service method properly, or supplied properly to the outgoing response.
The
greetings.listGreeting
method returns several Greetings, so we use a
GreetingCollection
message class that supports this.
The name and version of the API is specified in the class decorator
@endpoints.api(name='helloworld', version='v1')
. A complete list of decorator
arguments is provided in the topic
Defining the API
.
Notice that a class used for the API must be a
ProtoRPC service class
, as shown above
in the line
class HelloWorldApi(remote.Service)
. (An Endpoints API is an RPC
service that provides remote methods accessible to external clients.)
Notice the difference in the API method decorators in the
listGreeting
and
getGreeting
methods. The
listGreeting
method supports GET requests with no
arguments, and therefore specifies the
predefined message_types.VoidMessage
for the request message. The
getGreeting method
supports a request containing
an argument in the querystring, so it must specify a
ResourceContainer
.
In both method decorators, we supply the path to specify a location at which the
method serves requests. The value specified is appended to the API path, for
example, if the value
hellogreeting
is specified, the path is
https://your-app-id/appspot.com/_ah/api/helloworld/v1/hellogreeting
. For
greetings.getGreeting
, the path is
hellogreeting/{id}
where
{id}
is
required or else your API method won't receive the incoming request argument.
Finally, code is provided to create the API server. You could optionally do this in a separate module if you wish. For more information, see Creating an API Server .
Next...
Next, we'll add a simple POST.
Continue to Writing the API: a Simple POST .