basic_with_auth

#

If you have not yet seen the source in basic, please take a look.

#
import endpoints
from google.appengine.ext import ndb
from protorpc import remote

from endpoints_proto_datastore.ndb import EndpointsModel
#

In this model definition, we have added an extra field owner to the model defined in basic. Since using auth, we will save the current user and query by the current user, so saving a user property on each entity will allow us to do this.

class MyModel(EndpointsModel):
#

By default, the ProtoRPC message schema corresponding to this model will have four fields: attr1, attr2, created and owner in an arbitrary order (the ordering of properties in a dictionary is not guaranteed).

  attr1 = ndb.StringProperty()
  attr2 = ndb.StringProperty()
  created = ndb.DateTimeProperty(auto_now_add=True)
#

The three properties above are represented by string fields, but the UserProperty below is represented in the ProtoRPC message schema as a message field — a field whose value is itself a message. To hold a user property, a custom ProtoRPC message class is defined in endpoints_proto_datastore.utils and is used to convert to and from the NDB property and the corresponding ProtoRPC field.

  owner = ndb.UserProperty()
#

Since we are using auth, we want to test with the Google APIs Explorer. By default, if allowed_client_ids is not specified, this is enabled by default. If you specify allowed_client_ids, you'll need to include endpoints.API_EXPLORER_CLIENT_ID in this list. This is necessary for auth tokens obtained by the API Explorer (on behalf of users) to be considered valid by our API.

@endpoints.api(name='myapi', version='v1', description='My Little API',
               audiences=[endpoints.API_EXPLORER_CLIENT_ID])
class MyApi(remote.Service):
#

To specify that this method requires authentication, we can simply set the keyword argument user_required to True in the MyModel.method decorator. The remaining arguments to the decorator are the same as in basic. Once user_required is set, the method will first determine if a user has been detected from the token sent with the request (if any was sent it all) and will return an HTTP 401 Unauthorized if no valid user is detected. In the case of a 401, the method will not be executed. Conversely, if method execution occurs, user_required=True will guarantee that the current user is valid.

  @MyModel.method(user_required=True,
                  path='mymodel', http_method='POST', name='mymodel.insert')
  def MyModelInsert(self, my_model):
#

Since user_required is True, we know endpoints.get_current_user will return a valid user.

    my_model.owner = endpoints.get_current_user()
#

Also note, since we don't override the default ProtoRPC message schema, API users can send an owner object in the request, but we overwrite the model property with the current user before the entity is inserted into the datastore and this put operation will only occur if a valid token identifying the user was sent in the Authorization header.

    my_model.put()
    return my_model
#

As above with MyModelInsert, we add user_required=True to the arguments passed to the MyModel.query_method decorator in basic. Therefore, only queries can be made by a valid user.

  @MyModel.query_method(user_required=True,
                        path='mymodels', name='mymodel.list')
  def MyModelList(self, query):
#

We only allow users to query the MyModel entities that they have created, so query using owner equal to the current user. Since user_required is set, we know get_current_user will return a valid user.

    return query.filter(MyModel.owner == endpoints.get_current_user())
#
application = endpoints.api_server([MyApi], restricted=False)
#

Head on to the next sample paging or head back to the main page.