Common Patterns

This section contains some approaches to common problems. If you have a recommedation, please feel free to reach out to us.

Adding extra information to messages

Sometimes you want additional information to go along with your model data, here’s a quick example:

import ferris3 as f3
import endpoints
import protopigeon
from protorpc import messages
from google.appengine.ext import ndb


# This is our example model.
# it has two basic properties plus one method that provides
# some extra information.
class Page(ndb.Model):
    title = ndb.StringProperty()
    content = ndb.TextProperty()

    def get_permissions():
        if endpoints.get_current_user().email() == 'admin@example.com':
            return ["read", "update", "delete"]
        else:
            return ["read"]


# We'll create a standard message for our Model. This will have
# the title and content fields.
PageMessage = f3.messages.model_message(Page)


# We'll use this message to hold the permissions.
class WithPermissions(messages.Message):
    permissions = messages.StringField(1, repeated=True)


# We'll use protopigeon to combine the two messages together.
# This message will have title, content, and permissions fields.
PageMessageWithPermissions = protopigeon.compose(PageMessage, WithPermissions)


@f3.auto_service
class PagesService(f3.Service):

    @f3.auto_method(returns=PageMessageWithPermissions)
    def get(self, request, id=(str,)):
        page = f3.ndb.get(id)
        if not page:
            raise f3.NotFoundException()

        # We serialize as usual using the combined message.
        # The serialization will handle the title and content fields.
        message = f3.messages.serialize(PageMessageWithPermissions, page)

        # Finally, we'll manually populate the permissions field.
        message.permissions = page.get_permissions()

        return message

Using custom properties with protopigeon

Sometimes it’s desired to use a custom property or to override the built-in behavior for serializing properties. Here’s an example:

import ferris3
import endpoints
import protopigeon
from protorpc import messages
from google.appengine.ext import ndb


# This is our custom property class.
# We want ferris / protopigeon to automatically
# serialize this in messages
class ExampleProperty(ndb.StringProperty):
    def _to_base_type(self, value):
        return "---" + str(value) + "---"

    def _from_base_type(self, value):
        return value.strip('-')


# A simple class that uses our custom property
class ExampleModel(ndb.Model):
    normal = ndb.StringProperty()
    custom = ExampleProperty()


# This converter will tell ferris / protopigeon how to
# handle our custom property.
class ExamplePropertyConverter(protopigeon.converters.Converter):
    @staticmethod
    def to_field(Model, property, count):
        return messages.StringField(count, repeated=property._repeated, required=property._required)


# This tells protopigeon about our converter.
protopigeon.converters.converters["ExampleProperty"] = ExamplePropertyConverter


# Everything else happens automatically.
@ferris3.auto_service
class CustomService(ferris3.Service):
    list = ferris3.hvild.list(ExampleModel)
    insert = ferris3.hvild.insert(ExampleModel)