Package: plone.rest
Plone RESTPurposeplone.rest allows you to use HTTP verbs such as GET, POST, PUT, DELETE, etc. inPlone.REST stands forRepresentational State Transfer.
It is a software architectural principle to create loosely coupled web APIs.plone.rest 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’ fullPlone REST APIis so you can create alternative endpoints tailored to specific usecases.
A number of these specific endpoints are already in active use.Audienceplone.rest is for experienced web developers who want to build their own HTTP/REST endpoints on top of Plone.If you want tousea ready-made full RESTful Plone API, you should useplone.restapi.
That package uses, and depends upon, this one.FeaturesRegistering RESTful service endpoints for the following HTTP verbs:GETPOSTPUTDELETEPATCHOPTIONSSupport for Dexterity and Archetypes-based content objectsContent negotiation: Services can be registered for arbitrary media types (e.g. ‘application/json’).Named services allows to register service endpoints for custom URLsRegistering RESTful Service Endpointsplone.rest allows you to register HTTP verbs for Plone content with ZCML.This is how you would register a PATCH request on Dexterity content:<plone:servicemethod="PATCH"accept="application/json"for="plone.dexterity.interfaces.IDexterityContent"factory=".service.Patch"permission="cmf.ModifyPortalContent"/>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 plone.rest ‘Service’ class and to implement a render method that returns the body of the response:from plone.rest import Service

class Patch(Service):

    def render(self):
        return '{"message": "PATCH: Hello World!"}'Content NegotiationTo access the service endpoint we 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/jsonor by adding an explicit traversal step to the path like so:PATCH /Plone/++api++/doc1 HTTP/1.1
Host: localhost:8080The server then will respond with ‘200 OK’:HTTP/1.1 200 OK
Content-Type: application/json

{
  "message": "PATCH: Hello World!"
}Why two methods?
Using the ‘Accept’ header is the intended way of RESTful APIs to get different responses from the same URL.
However, if it comes to caching the response in an web accelerator like Varnish or Cloudflare, additional challenges are added.
Setting theVaryheader to ‘Vary: Accept’ helps to a certain degree in Varnish.
But cache pollution may happen, because different browsers send different headers on normal HTML requests.
Hosted services like Cloudflare just do not support the ‘Vary’ usage and can not be used for sites with REST calls.
Thus a second option with different URLs is needed.You can try this out on the command line:$http--authadmin:adminPATCHlocalhost:8080/Plone/doc1Accept:application/jsonNoteYou have to install httpie (pip install httpie) to make this example work.Here is a list of examples for all supported HTTP verbs:GET:$ http --auth admin:admin GET localhost:8080/Plone/doc1 Accept:application/json
$ http --auth admin:admin GET localhost:8080/Plone/++api++/doc1POST:$ http --auth admin:admin POST localhost:8080/Plone/doc1 Accept:application/json
$ http --auth admin:admin POST localhost:8080/Plone/++api++/doc1PUT:$ http --auth admin:admin PUT localhost:8080/Plone/doc1 Accept:application/json
$ http --auth admin:admin PUT localhost:8080/Plone/++api++/doc1DELETE:$ http --auth admin:admin DELETE localhost:8080/Plone/doc1 Accept:application/json
$ http --auth admin:admin DELETE localhost:8080/Plone/++api++/doc1PATCH:$ http --auth admin:admin PATCH localhost:8080/Plone/doc1 Accept:application/json
$ http --auth admin:admin PATCH localhost:8080/Plone/++api++/doc1OPTIONS:$ http --auth admin:admin OPTIONS localhost:8080/Plone/doc1 Accept:application/json
$ http --auth admin:admin OPTIONS localhost:8080/Plone/++api++/doc1Named ServicesNamed services can be registered by providing a ‘name’ attribute in the service directive:<plone:servicemethod="GET"accept="application/json"for="Products.CMFPlone.interfaces.IPloneSiteRoot"factory=".service.Search"name="search"permission="zope2.View"/>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/jsonService endpoints can also be accessed using the traverser:GET /Plone/++api++/search HTTP/1.1
Host: localhost:8080Additional Path SegmentsTo handle additional path segments after the service url like/Plone/myservice/1/2a service has to implementIPublishTraverse. The following example simply
stores all path segments in an array inself.params.fromplone.restimportServicefromzope.interfaceimportimplementerfromzope.publisher.interfacesimportIPublishTraverse@implementer(IPublishTraverse)classMyService(Service):def__init__(self,context,request):super(MyService,self).__init__(context,request)self.params=[]defpublishTraverse(self,request,name):self.params.append(name)returnselfdefrender(self):return{'service':'named get','params':self.params}See also the implementation of the workflow transition endpoint in
plone.restapi for an other example.CORSplone.rest allows you to define CORS policies for services in ZCML. The
following example defines a policy for all services.<plone:CORSPolicyallow_origin="http://example.net"allow_methods="DELETE,GET,OPTIONS,PATCH,POST,PUT"allow_credentials="true"expose_headers="Content-Length,X-My-Header"allow_headers="Accept,Authorization,Content-Type,X-Custom-Header"max_age="3600"/>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.<plone:CORSPolicyfor="Products.CMFPlone.interfaces.IPloneSiteRoot"layer="myproduct.interfaces.IMyBrowserLayer"allow_origin="*"allow_methods="GET"/>The CORSPolicy directive supports the following options:allow_originOrigins that are allowed to access the resource. Either a comma separated
list of origins, e.g. “http://example.net,http://mydomain.com” or “*”.allow_methodsA 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 registered are allowed.allow_credentialsIndicates whether the resource supports user credentials in the request.allow_headersA comma separated list of request headers allowed to be sent by the client,
e.g. “X-My-Header”expose_headersA comma separated list of response headers clients can access,
e.g. “Content-Length,X-My-Header”.max_ageIndicates how long the results of a preflight request can be cached.forSpecifies the interface for which the CORS policy is registered. If this
attribute is not specified, the CORS policy applies to all objects.layerA 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.InstallationInstall plone.rest by adding it to your buildout:[buildout]

 ...

 eggs =
     plone.restand then running “bin/buildout”Plone/Python Supportplone.rest 4.x.x supports Plone 5.2 and 6.x on Python 3.8 and newer.plone.rest 3.x.x supports Plone 5.2 on Python 2.7 and 3.6 to 3.8 and Plone 6.0 on Python 3.8 to 3.11.If you need to use Plone 4.3, 5.0, or 5.1 on Python 2.7, check out plone.rest 2.x.x or 1.x.x.Redirectsplone.rest will handle redirects created byplone.app.redirectorpretty
much the same way as regular Plone.If a redirect exists for a given URL, aGETrequest will be answered with302, and the new location for the resource is indicated in theLocationheader:HTTP/1.1 302 Moved Temporarily

Content-Type: application/json
Location: http://localhost:8080/Plone/my-folder-new-locationAny other request method than GET (POST,PATCH, …) will be answered
with307 Temporary Redirect. This status code instructs the client that
it should NOT switch the method, but retry (if desired) the request with thesamemethod at the new location.In practice, both the Pythonrequestslibrary a well as Postman seem to
honour this behavior by default.ContributeIssue Tracker:https://github.com/plone/plone.rest/issuesSource Code:https://github.com/plone/plone.restDocumentation:https://pypi.org/project/plone.rest/SupportThis package is maintained by Timo Stollenwerk <tisto@plone.org>.If you are having issues, pleaselet us know.Creditsplone.rest has been written by Timo Stollenwerk (kitconcept GmbH) and Ramon Navarro Bosch (Iskra).plone.rest was added as a Plone core package with Plone 5.2 (seehttps://github.com/plone/Products.CMFPlone/issues/2177).LicenseThe project is licensed under the GPLv2.Changelog4.1.3 (2024-01-26)Internal:Update configuration files.
[plone devs] (93e1ab65)4.1.2 (2023-10-28)Bug fixes:Fix parsing mimetypes in Accept header with an extra slash. @djay (#153)4.1.1 (2023-10-23)Internal:Fix test leakage, enabling the publication check when it shouldn’t be active. @jaroel (#168)4.1.0 (2023-10-18)New features:Add support for Python 3.12. @tisto (#167)Bug fixes:Make REST endpoints check for acquired items. @jaroel (#166)4.0.0 (2023-09-22)Breaking changes:Drop support for Python 2.7, 3.6, and 3.7 @tisto (#141)3.0.1 (2023-09-21)Bug fixes:When++api++is in the url multiple times, redirect to the proper url.
When the url is badly formed, for example++api++/something/++api++, give a 404 NotFound.
Fixes a denial of service.
Seesecurity advisory.
[maurits] (#1)3.0.0 (2023-01-29)Breaking changes:Change the HTTP status from 301 (Moved Permanently) to 302 (Found) for GET requests and to 307 (Temporary Redirect) for other request methods.
This fixes problems when an existing redirect is re-used.
[mamico] (#135)Drop official support for Plone 4.3, 5.0 and 5.1 (most likely the package will continue to work though)
[tisto] (#140)New features:Add official support for Plone 6
[tisto] (#143)Add official support for Python 3.9, 3.10, and 3.11
[tisto] (#147)2.0.0 (2022-10-15)Bug fixes:Re-release 2.0.0a6 as 2.0.0 [tisto] (#136)2.0.0a5 (2022-04-07)Bug fixes:Fix an infinite loop with redirections from parent to child [ericof] (#133)2.0.0a4 (2022-03-24)Bug fixes:++api++ traverser should be kept on 30x redirections [mamico] (#132)2.0.0a3 (2022-02-12)Bug fixes:++api++ traverser should be kept on 30x redirections [mamico] (#127)2.0.0a2 (2022-01-25)Bug fixes:Fix typo inREADME.rst[jensens] (#123)Use document_view as default for site root.
[agitator] (#126)Resolve all the deprecation warnings that originate in this package’s code that are
exposed by running the tests that do not stem from backwards compatibility we support.
[rpatterson] (#128)2.0.0a1 (2021-10-05)New features:Add a traverser++api++as an alternative to mark a request as REST request.
[jensens] (#113)1.6.2 (2021-02-20)Bug fixes:Explicitly makeallow_credentialsrequired in CORS policy.
This was the default for Bool fields until and including zope.schema 6.0.1, but in 6.1.0 this changed.
[maurits] (#104)1.6.1 (2020-03-22)Bug fixes:CORS preflight should happen for all error codes, fixes #101
[sneridagh] (#101)1.6.0 (2019-10-15)New features:Remove CMFPlone and make plone.app.redirector dependency optional [timo] (#81)1.5.1 (2019-10-15)Brown bag release.1.5.0 (2019-10-13)Brown bag release.1.4.0 (2018-11-08)New features:Python 3 compatibility
[tschorr,pbauer,frapell]1.3.0 (2018-09-11)New features:Remove unnecessary dependency on Products.CMFPlone.
Import ISiteRoot from Products.CMFCore.interfaces instead of
IPloneSiteRoot from Products.CMFPlone.interfaces.siteroot.
[jordic]1.2.0 (2018-06-29)New features:Add support for redirects from plone.app.redirector.
[lgraf]1.1.1 (2018-06-22)Bugfixes:Re-release 1.1.0.1.1.0 (2018-06-22)New features:Get rid of Products.Five.metaclass dependency for Zope 4 compatibility.
[timo]1.0.0 (2018-01-17)New features:Add support for Plone 5.1.
[timo]Add Plone 4.3, 5.0 and 5.1 to list classifiers in setup.py.
[timo]Set development status to production/stable in setup.py.
[timo]1.0b1 (2017-05-14)Bugfixes:Do not render service in preflight requests when no CORS policy was defined.
Fixes:https://github.com/plone/plone.rest/issues/63[buchi]1.0a7 (2016-11-21)Bugfixes:Do not handle view namespace at all. This fixes:https://github.com/plone/plone.rest/issues/50[buchi]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 being 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 overridden by other traversal adapters.
[buchi]1.0a3 (2015-12-16)Release fix. 1.0a2 was a brown-bag release. This fixeshttps://github.com/plone/plone.rest/issues/34.
[timo]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 likeGET /Plone/searchorGET /Plone/doc1/versions/1using 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]