Domanda

I am trying to use endpoints to update some JSON values in my datastore. I have the following Datastore in GAE...

class UsersList(ndb.Model):
    UserID = ndb.StringProperty(required=True)
    ArticlesRead = ndb.JsonProperty()
    ArticlesPush = ndb.JsonProperty()

In general what I am trying to do with the API is have the method take in a UserID and a list of articles read (with an article being represented by a dictionary holding an ID and a boolean field saying whether or not the user liked the article). My messages (centered on this logic) are the following...

class UserID(messages.Message):
    id = messages.StringField(1, required=True)


class Articles(messages.Message):
    id = messages.StringField(1, required=True)
    userLiked = messages.BooleanField(2, required=True)


class UserIDAndArticles(messages.Message):
    id = messages.StringField(1, required=True)
    items = messages.MessageField(Articles, 2, repeated=True)


class ArticleList(messages.Message):
    items = messages.MessageField(Articles, 1, repeated=True)

And my API/Endpoint method that is trying to do this update is the following...

@endpoints.method(UserIDAndArticles, ArticleList,
                  name='user.update',
                  path='update',
                  http_method='GET')
def get_update(self, request):
    userID = request.id
    articleList = request.items
    queryResult = UsersList.query(UsersList.UserID == userID)

    currentList = []

    #This query always returns only one result back, and this for loop is the only way
    # I could figure out how to access the query results.
    for thing in queryResult:
        currentList = json.loads(thing.ArticlesRead)

    for item in articleList:
        currentList.append(item)

    for blah in queryResult:
        blah.ArticlesRead = json.dumps(currentList)
        blah.put()

    for thisThing in queryResult:
        pushList = json.loads(thisThing.ArticlesPush)

    return ArticleList(items = pushList)

I am having two problems with this code. The first is that I can't seem to figure out (using the localhost Google APIs Explorer) how to send a list of articles to the endpoints method using my UserIDAndArticles class. Is it possible to have a messages.MessageField() as an input to an endpoint method?

The other problem is that I am getting an error on the 'blah.ArticlesRead = json.dumps(currentList)' line. When I try to run this method with some random inputs, I get the following error...

TypeError: <Articles
 id: u'hi'
 userLiked: False> is not JSON serializable

I know that I have to make my own JSON encoder to get around this, but I'm not sure what the format of the incoming request.items is like and how I should encode it.

I am new to GAE and endpoints (as well as this kind of server side programming in general), so please bear with me. And thanks so much in advance for the help.

È stato utile?

Soluzione

A couple things:

  • http_method should definitely be POST, or better yet PATCH because you're not overwriting all existing values but only modifying a list, i.e. patching.
  • you don't need json.loads and json.dumps, NDB does it automatically for you.
  • you're mixing Endpoints messages and NDB model properties.

Here's the method body I came up with:

# get UsersList entity and raise an exception if none found.
uid = request.id
userlist = UsersList.query(UsersList.UserID == uid).get()
if userlist is None:
    raise endpoints.NotFoundException('List for user ID %s not found' % uid)

# update user's read articles list, which is actually a dict.
for item in request.items:
    userslist.ArticlesRead[item.id] = item.userLiked
userslist.put()

# assuming userlist.ArticlesPush is actually a list of article IDs.
pushItems = [Article(id=id) for id in userlist.ArticlesPush]
return ArticleList(items=pushItems)

Also, you should probably wrap this method in a transaction.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top