Question

I would like to create a BaseModel that is an EndpointsModel to contain properties common across all my models (ie. created_at, modified_at). Then I would like to create a User model that extends that BaseModel.

However, I'm running into an issue where when I look at my "user.create" method in the API Explorer, the request body only shows only shows the BaseModel properties of created_at and modified_at, but not the username property.

Here's what I have:

from endpoints_proto_datastore.ndb import EndpointsModel
from google.appengine.ext import ndb

class BaseModel(EndpointsModel):
  created_at = ndb.DateTimeProperty(auto_now_add=True)
  modified_at = ndb.DateTimeProperty(auto_now=True)

class User(BaseModel):
  username = ndb.StringProperty(required=True)

Here's the API built using Google Cloud Endpoints:

import endpoints
from google.appengine.ext import ndb
from models import User
from protorpc import remote

@endpoints.api(name='user', version='v1',
               description='API for User Management')
class UserApi(remote.Service):

  @User.method(name='user.create', path='user'):
  def create_user(self, user):
    user.put()
    return user

application = endpoints.api_server([UserApi])
Was it helpful?

Solution

If you go to http://localhost:8080/_ah/api/discovery/v1/apis/user/v1/rest you'll see the discovery document generated by your API. Note that (toward the bottom) the create method on the user resource is shown as taking a BaseModel rather than a User.

Now I don't know why this happens precisely—it's definitely related to the magic being done by EndpointsModel—but I have been able to achieve the result you want by switching the inheritance around, and treating BaseModel like a mixin rather than a base class, this way the User model can inherit directly from EndpointsModel:

class BaseModel:
    created_at = ndb.DateTimeProperty(auto_now_add=True)
    modified_at = ndb.DateTimeProperty(auto_now=True)

class User(BaseModel, EndpointsModel):
    username = ndb.StringProperty(required=True)

It makes sense then to rename BaseModel to something that makes more explicit it's a mixin now.

If you check the same discovery document (or API Explorer) you'll notice create takes a User message after this change.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top