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.
By default, the ProtoRPC message schema corresponding to this model will
have four fields:
in an arbitrary order (the ordering of properties in a dictionary is not
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
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
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
user_required=True will guarantee that the current user is
@MyModel.method(user_required=True, path='mymodel', http_method='POST', name='mymodel.insert') def MyModelInsert(self, my_model):
True, we know
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
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)