Writing a serializer or a deserializer#
In plone.restapi we have a hierarchy, several levels deep, of serializer and
deserializer adapters. Keep in mind that "serializing" is the operation where
we transform Python objects to a representation (JSON) and deserializing is
when we take that representation (JSON coming from the browser POST, for
example) and convert it to live Python objects. The (de)serializers, with the
type-based lookups are a great example of ZCML use, as they're all implemented
as adapters for the content+request => ISomeSerializationInferface.
Here's that logic chain of that hierarchy:
- content based, where the class of the context item is used as discriminator in the adaptor to - plone.restapi.interfaces.ISerializeToJson(and the counterpart- IDeserializeToJson. See the DX Content serializer.
- field based, used when processing DX Content, where each field/property is adapted for endpoint serialization with the - IFieldSerializer/- IFieldDeserializer. See the DX Field serializers.
- block based, where we take the JSON data bits that represent a Volto block data and transform it (see the Writing a block transform chapter). 
- block value based, where each Python basic data value needs to be transformed into a JSON-compatible representation, with the - IJsonCompatibleadaptor (use- json_compatible()helper for this. See the converters.py module with these basic serializers.
Here's how the Folder serializer looks like:
@implementer(ISerializeToJson)
@adapter(IDexterityContainer, Interface)
class SerializeFolderToJson(SerializeToJson):
    def _build_query(self):
        path = "/".join(self.context.getPhysicalPath())
        query = {
            "path": {"depth": 1, "query": path},
            "sort_on": "getObjPositionInParent",
        }
        return query
    def __call__(self, version=None, include_items=True):
        folder_metadata = super().__call__(version=version)
        folder_metadata.update({"is_folderish": True})
        result = folder_metadata
        include_items = self.request.form.get("include_items", include_items)
        include_items = boolean_value(include_items)
        if include_items:
            query = self._build_query()
            catalog = getToolByName(self.context, "portal_catalog")
            brains = catalog(query)
            batch = HypermediaBatch(self.request, brains)
            result["items_total"] = batch.items_total
            if batch.links:
                result["batching"] = batch.links
            if "fullobjects" in list(self.request.form):
                result["items"] = getMultiAdapter(
                    (brains, self.request), ISerializeToJson
                )(fullobjects=True)["items"]
            else:
                result["items"] = [
                    getMultiAdapter((brain, self.request), ISerializeToJsonSummary)()
                    for brain in batch
                ]
        return result