Writing a serializer or a deserializer#
In plone.restapi we have an hierarchy, several levels deep, of serializers and deserializers 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.
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).
value based, where each Python basic data value needs to be transformed into a JSON-compatible representation, with the
IJsonCompatible
adaptor (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