Writing a custom serializer for Plone REST API
Tags: plone, restapi, serializer
Published: 2020-12-08 13:27:48

---
title: Writing a custom serializer for Plone REST API
published: true
date: 2018-08-05 22:00:00 UTC
tags: plone,plone,restapi,serializer
canonical_url: http://mrtango.planetcrazy.de/writing-a-custom-serializer-for-plone-rest-api.html
---

The following code shows two custom FieldSerializer adapters which handle the values of Choice and MultiChoice (Collection) fields. For doing this, we register one adapter for the IChoice interface and one adapter for ICollection interface. Both also support vocabularies provided by collective.taxonomy.

By default the Plone REST API would give us just the plain tokens back, because that's what is actually stored when you use a Selection or Multiselection field. But on the client side we want the token and also the title, so that we can easily show it. Therefor we want something like this as the value for a Choice field.

## Expected response

### IChoice field

```
"solution\_category": {
    "title": "A nice title",
    "token": "a-nice-title"
},

```

### ICollection field

```
"solution\_category": [
    {
        "title": "A nice title",
        "token": "a-nice-title"
    },
    {
        "title": "An awesome title",
        "token": "an-awesome-title"
    },
]

```

## Implementation

<tt>restapi.py</tt>

```
from plone.dexterity.interfaces import IDexterityContent
from plone.restapi.interfaces import IFieldSerializer
from plone.restapi.serializer.converters import json\_compatible
from zope.component import adapter
from zope.component import getUtility
from zope.interface import implementer
from zope.interface import Interface
from zope.schema.interfaces import IChoice
from zope.schema.interfaces import ICollection
from zope.schema.interfaces import IVocabularyFactory

def \_get\_vocab\_term(context, field, value):
    """ Get vocab term dict
 returns: {'token': token, 'title': title}
 """
    vocab\_term = {
        'token': None,
        'title': None,
    }
    vocab\_term['token'] = value
    factory = getUtility(IVocabularyFactory, field)
    if not factory:
        return vocab\_term

    # collective.taxonomy support:
    if hasattr(factory, 'translate'):
        vocab\_term['title'] = \_get\_taxonomy\_vocab\_title(
            context,
            factory,
            value,
        )
    elif IVocabularyFactory.providedBy(factory):
        vocab\_term['title'] = \_get\_vocab\_title(
            context,
            factory,
            value,
        )
    return vocab\_term

def \_get\_taxonomy\_vocab\_title(context, factory, value):
        vocab\_title = factory.translate(
            value,
            context=context,
        )
        return vocab\_title

def \_get\_vocab\_title(context, factory, value):
    vocab = factory(context)
    vocab\_title = vocab.getTermByToken(value).title
    return vocab\_title

class BaseFieldSerializer(object):

    def \_\_init\_\_(self, field, context, request):
        self.context = context
        self.request = request
        self.field = field

    def \_\_call\_\_(self):
        return json\_compatible(self.get\_value())

@adapter(IChoice, IDexterityContent, Interface)
@implementer(IFieldSerializer)
class ChoiceFieldSerializer(BaseFieldSerializer):
    """
 """
    def get\_value(self, default=None):
        value = getattr(
            self.field.interface(self.context),
            self.field.\_\_name\_\_,
            default,
        )
        if not value:
            return

        term = \_get\_vocab\_term(
            self.context,
            self.field.vocabularyName,
            value,
        )
        return term

@adapter(ICollection, IDexterityContent, Interface)
@implementer(IFieldSerializer)
class CollectionFieldSerializer(BaseFieldSerializer):
    """
 """
    def get\_value(self, default=None):
        terms = []
        values = getattr(
            self.field.interface(self.context),
            self.field.\_\_name\_\_,
            default,
        )
        if not values:
            return
        if not IChoice.providedBy(self.field.value\_type):
            return

        for value in values:
            term = \_get\_vocab\_term(
                self.context,
                self.field.value\_type.vocabularyName,
                value,
            )
            terms.append(term)
        return terms

```

## Registration

To activate this, we need to register the two adapters:

<tt>configure.zcml</tt>

```
<adapter factory=".restapi.ChoiceFieldSerializer" />
<adapter factory=".restapi.CollectionFieldSerializer" />

```