Skip to main content

Plone support for HTTP verbs.

Project description Code Health Latest Version Egg Status License

Plone REST

Purpose allows you to use HTTP verbs such as GET, POST, PUT, DELETE, etc. in Plone.

REST stands for Representational State Transfer. It is a software architectural principle to create loosely coupled web APIs. provides the basic infrastructure that allows us to build RESTful endpoints in Plone.

The reason for separating this infrastructure into a separate package from the ‘main’ full Plone REST API is so you can create alternative endpoints tailored to specific usecases. A number of these specific endpoints are already in active use.

Audience is for experienced web developers who want to build their own HTTP/REST endpoints on top of Plone.

If you want to use a ready-made full RESTful Plone API, you should use plone.restapi. That package uses, and depends upon, this one.


  • Registering RESTful service endpoints for the following HTTP verbs:

    • GET

    • POST

    • PUT

    • DELETE

    • PATCH


  • Support for Dexterity and Archetypes-based content objects

  • Content negotiation: Services can be registered for arbitrary media types (e.g. ‘application/json’).

  • Named services allows to register service endpoints for custom URLs

Registering RESTful Service Endpoints allows you to register HTTP verbs for Plone content with ZCML.

This is how you would register a PATCH request on Dexterity content:


You have to specify the HTTP verb (GET, POST, PUT, DELETE, HEAD, OPTIONS), the media type used for content negotiation, the interface for the content objects, the factory class that actually returns the content and the permission required to access the service.

The factory class needs to inherit from the ‘Service’ class and to implement a render method that returns the body of the response:

from import Service

class Patch(Service):

    def render(self):
        return '{"message": "PATCH: Hello World!"}'

Content Negotiation

To access the service endpoint we just created we have to send a GET request to a Dexterity object by setting the ‘Accept’ header to ‘application/json’:

PATCH /Plone/doc1 HTTP/1.1
Host: localhost:8080
Accept: application/json

The server then will respond with ‘200 OK’:

HTTP/1.1 200 OK
Content-Type: application/json

  "message": "PATCH: Hello World!"

You can try this out on the command line:

$ http --auth admin:admin PATCH localhost:8080/Plone/doc1 Accept:application/json

Here is a list of examples for all supported HTTP verbs:


$ http --auth admin:admin GET localhost:8080/Plone/doc1 Accept:application/json


$ http --auth admin:admin POST localhost:8080/Plone/doc1 Accept:application/json


$ http --auth admin:admin PUT localhost:8080/Plone/doc1 Accept:application/json


$ http --auth admin:admin DELETE localhost:8080/Plone/doc1 Accept:application/json


$ http --auth admin:admin PATCH localhost:8080/Plone/doc1 Accept:application/json


$ http --auth admin:admin OPTIONS localhost:8080/Plone/doc1 Accept:application/json

Named Services

Named services can be registered by providing a ‘name’ attribute in the service directive:


This registers a service endpoint accessible at the site root using the following request:

GET /Plone/search HTTP/1.1
Host: localhost:8080
Accept: application/json

Additional Path Segments

To handle additional path segments after the service url like /Plone/myservice/1/2 a service has to implement IPublishTraverse. The following example simply stores all path segments in an array in self.params.

from import Service
from zope.interface import implements
from zope.publisher.interfaces import IPublishTraverse

class MyService(Service):


    def __init__(self, context, request):
        super(MyService, self).__init__(context, request)
        self.params = []

    def publishTraverse(self, request, name):
        return self

    def render(self):
        return {'service': 'named get', 'params': self.params}

See also the implementation of the workflow transition endpoint in plone.restapi for an other example.

CORS allows you to define CORS policies for services in ZCML. The following example defines a policy for all services.


CORS policies can be bound to specific interfaces of content objects and to specific browser layers. This allows us to define different policies for different content types or to override existing policies. The following example defines a policy for the site root.


The CORSPolicy directive supports the following options:


Origins that are allowed to access the resource. Either a comma separated list of origins, e.g. “,” or “*”.


A comma separated list of HTTP method names that are allowed by this CORS policy, e.g. “DELETE,GET,OPTIONS,PATCH,POST,PUT”. If not specified, all methods for which there’s a service registerd are allowed.


Indicates whether the resource supports user credentials in the request.


A comma separated list of request headers allowed to be sent by the client, e.g. “X-My-Header”


A comma separated list of response headers clients can access, e.g. “Content-Length,X-My-Header”.


Indicates how long the results of a preflight request can be cached.


Specifies the interface for which the CORS policy is registered. If this attribute is not specified, the CORS policy applies to all objects.


A browser layer for which this CORS policy is registered. Useful for overriding existing policies or for making them available only if a specific add-on has been installed.


Install by adding it to your buildout:



 eggs =

and then running “bin/buildout”



This package is maintained by Timo Stollenwerk <> and Ramon Navarro Bosch <>.

If you are having issues, please let us know.


The project is licensed under the GPLv2.


1.1.1 (2018-06-22)

  • Re-release 1.1.0.

1.1.0 (2018-06-22)

  • Get rid of Products.Five.metaclass dependency for Zope 4 compatibility. [timo]

1.0.0 (2018-01-17)

  • Add support for Plone 5.1. [timo]

  • Add Plone 4.3, 5.0 and 5.1 to list classifiers in [timo]

  • Set development status to production/stable in [timo]

1.0b1 (2017-05-14)


1.0a7 (2016-11-21)


1.0a6 (2016-05-22)

  • Add support for CORS policies. [buchi]

  • Remove JSON render implementation in service base class. Services must provide their own render implementation. [buchi]

  • Fallback to regular views during traversal to ensure compatibility with views beeing called with a specific Accept header. [buchi]

1.0a5 (2016-02-27)

  • Implement permission handling. The permission required to access a service must be declared in the service directive. [buchi]

  • Register services with the Zope configuration system. This provides better conflict detection and resolution. [buchi]

  • Improve message for 404 Not Found exceptions (don’t return HTML). [lgraf]

  • Add regression tests for service dispatching. [lgraf]

  • Restrict traversal of REST requests to content objects. This allows us to override existing views with a named service (e.g. /search). [buchi]

  • Allow virtual hosting scenarios. This fixes #48. [tomgross]

1.0a4 (2016-02-07)

  • Refactor Dexterity tests to make sure services return the correct object. [timo]

  • Add support for browser layers. REST services can now be registered to a specific browser layer using the ‘layer’ attribute. [buchi]

  • Remove request method specific marker interfaces (IGET, IPOST, etc.) because they’re no longer required for service lookup. [buchi]

  • Add support for content negotiation. REST services are no longer hardwired to ‘application/json’ Accept headers. Instead the media type can be configured with the service directive. [buchi]

  • Refactor traversal of REST requests by using a traversal adapter on the site root instead of a traversal adapter for each REST service. This prevents REST services from being overriden by other traversal adapters. [buchi]

1.0a3 (2015-12-16)

1.0a2 (2015-12-10)

  • Simplify patch of DynamicType pre-traversal hook and actually make it work with Archetypes. [buchi]

  • Render errors as JSON. [jone]

  • Add support for named services which allows registering services like GET /Plone/search or GET /Plone/doc1/versions/1 using a ‘name’ attribute. [jone, lukasgraf, buchi]

  • Remove “layer” from service directive for now, because it is not yet implemented properly. [jone]

1.0a1 (2015-08-01)

  • Initial release. [bloodbare, timo]

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution (98.6 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page