DEV Community

Maik Derstappen
Maik Derstappen

Posted on • Originally published at mrtango.planetcrazy.de on

Writing a custom service for Plone REST API

Plone REST API expand

Plone REST API services allow you to use the Expansion functionionality, to reduce the request on the client side. This way you can include additional informations, you want to show together with your main content in one single response. The Plone REST API already provides some useful services like the Breadcrumb service. Together with the Expansion flag, you can easily expand specific service informations into the main response.

For details about the Expension function see here:https://plonerestapi.readthedocs.io/en/latest/expansion.html

Implementation

We create the following structure in our Plone package:

services/
├── configure.zcml
├── __init__.py
└── related_articles
    ├── configure.zcml
    ├── get.py
    ├── __init__.py

Enter fullscreen mode Exit fullscreen mode

In the services folder, we have this configure.zcml

<configure xmlns="http://namespaces.zope.org/zope">

  <include package=".related\_articles" />

</configure>

Enter fullscreen mode Exit fullscreen mode

also add this line to the parent configure.zcml:

<include package=".services" />

Enter fullscreen mode Exit fullscreen mode

to register the actual service, we need the following zcml config inside the related_articles folder:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:plone="http://namespaces.plone.org/plone">

  <adapter factory=".get.RelatedArticles" name="related-articles"/>

  <plone:service
    method="GET"
    for="zope.interface.Interface"
    factory=".get.RelatedArticlesGet"
    name="@related-articles"
    permission="zope2.View"
    />

</configure>

Enter fullscreen mode Exit fullscreen mode

The service code looks as follow:

get.py

# -\*- coding: utf-8 -\*-
from plone import api
from plone.restapi.interfaces import IExpandableElement
from plone.restapi.services import Service
from zope.component import adapter
from zope.interface import Interface
from zope.interface import implementer

@implementer(IExpandableElement)
@adapter(Interface, Interface)
class RelatedArticles(object):

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

    def \_\_call\_\_(self, expand=False):
        result = {
            'related-articles': {
                '@id': '{}/@related-articles'.format(
                    self.context.absolute\_url(),
                ),
            },
        }
        if not expand:
            return result

        solution\_categories = [c for c in self.context.solution\_category]
        article\_brains = api.content.find(
            portal\_type="Chapter",
            solution\_category={
                'query': solution\_categories,
                'operator': 'and',
            }
        )
        items = []
        for article in article\_brains:
            items.append({
                'title': article.Title,
                '@id': article.getURL(),
            })

        result['related-articles']['items'] = items
        return result

class RelatedArticlesGet(Service):

    def reply(self):
        related\_articles = RelatedArticles(self.context, self.request)
        return related\_articles(expand=True)['related-articles']

Enter fullscreen mode Exit fullscreen mode

The service is using the plone.api to find all related objects of the portal_type Chapter and createds a list of dicts with the @id and title of each Chapter. Together with the Expansion flag, the client can expand this as follow:

http://localhost:7080/Plone/some-content?expand=related-articles

You will find the expanded service info inside of the @component section:

"@components": {
    "actions": {
        "@id": "http://localhost:7080/Plone/some-content/@actions"
    },
    "breadcrumbs": {
        "@id": "http://localhost:7080/Plone/some-content/@breadcrumbs"
    },
    "navigation": {
        "@id": "http://localhost:7080/Plone/some-content/@navigation"
    },
    "related-articles": {
        "@id": "http://localhost:7080/Plone/some-content/@related-articles",
        "items": [{
            "@id": "http://localhost:7080/Plone/articles/harvesting",
            "title": "Harvesting"
        }]
    },
    "workflow": {
        "@id": "http://localhost:7080/Plone/some-content/@workflow"
    }
},

Enter fullscreen mode Exit fullscreen mode

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay