Hide
Python

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:

  1. Create a new folder named helloendpoints (the folder name is arbitrary, but you will use it later in this tutorial).

  2. 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: this must be /_ah/spi for Endpoints, NOT /_ah/api!
    - 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.

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

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

  5. 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,))
    
  6. Finally, add the API server code:

    APPLICATION = endpoints.api_server([HelloWorldApi])
    

    The casing of APPLICATION in this line must match the casing in the app.yaml file in the line script: helloworld_api.APPLICATION.

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

  1. Change to the helloworld parent directory and start the API in the development server by invoking:

    ~/path/to/python/sdk/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
    
  2. 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.

  3. Click helloworld to display the available methods. Click helloworld.greetings.getGreetings to display the Explorer form for it:

    greetings.GetGreetings

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

  5. Notice the display of the request and response. In the Response, you'll see the OK result and the returned message, hello world!.

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