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

Top comments (0)