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 counterpartIDeserializeToJson. 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 (usejson_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