Writing a custom service for Plone REST API
Tags: plone, restapi, service
Published: 2020-12-08 13:28:10

---
title: Writing a custom service for Plone REST API
published: true
date: 2018-08-07 22:00:00 UTC
tags: plone,plone,restapi,service
canonical_url: http://mrtango.planetcrazy.de/writing-a-custom-service-for-plone-rest-api.html
---

## 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](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

```

In the services folder, we have this configure.zcml

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

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

</configure>

```

also add this line to the parent configure.zcml:

```
<include package=".services" />

```

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>

```

The service code looks as follow:

<tt>get.py</tt>

```
# -\*- 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']

```

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](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"
    }
},

```