Restapi¶
Changes and enhancments on the Plone RestAPI by 7inOne
File GET¶
For the original, check Plone RestAPI File GET for details.
In case of files 7inOne provides an option to activate direct downloads of files via the RestAPI GET endpoint.
Via registry the value of wcs.backend.api.directdownload can be activated, this enables the direct download feature. This feature only works with the portal_type File.
http
GET /Plone/any-file.pdf HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET http://localhost:8080/Plone/any-file.pdf -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/any-file.pdf', headers={'Accept': 'application/json'})
Response:
File download
This behavior can be overriden again by a querystring variable named json:
http
GET /Plone/any-file.pdf?json=true HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET 'http://localhost:8080/Plone/any-file.pdf?json=true' -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/any-file.pdf?json=true', headers={'Accept': 'application/json'})
Enhanced Field Serialization¶
File Fields with Download URLs¶
File fields include enhanced download URLs with filename and cache-busting timestamps.
http
GET /Plone/my-document HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET http://localhost:8080/Plone/my-document -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/my-document', headers={'Accept': 'application/json'})
Response shows file field with enhanced download URL:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/plone/my-document",
"@type": "Document",
"title": "My Document",
"file": {
"@type": "File",
"content-type": "application/pdf",
"download": "http://localhost:8080/plone/my-document/@@download/file/document.pdf?_t=1694847123456",
"filename": "document.pdf",
"size": 245760
}
}
Link Fields Resolution¶
TextLine fields using LinkFieldWidget automatically resolve internal links from resolveuid to absolute URLs.
http
GET /Plone/page-with-links HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET http://localhost:8080/Plone/page-with-links -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/page-with-links', headers={'Accept': 'application/json'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/plone/page-with-links",
"@type": "Document",
"title": "Page with Links",
"external_link": "https://example.com",
"internal_link": "http://localhost:8080/plone/target-page",
"related_content": "http://localhost:8080/plone/related-document"
}
Staging Folder Serialization¶
Working Copy with Baseline Items¶
When viewing a working copy folder, items include both working copy content and baseline content for easier navigation.
http
GET /Plone/folder-workingcopy?include_items=true HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET 'http://localhost:8080/Plone/folder-workingcopy?include_items=true' -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/folder-workingcopy?include_items=true', headers={'Accept': 'application/json'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/plone/folder-workingcopy",
"@type": "Folder",
"title": "My Folder (Working Copy)",
"is_folderish": true,
"items_total": 4,
"items": [
{
"@id": "http://localhost:8080/plone/folder-workingcopy/new-page",
"@type": "Document",
"title": "New Page",
"review_state": "private"
},
{
"@id": "http://localhost:8080/plone/folder-workingcopy/modified-page",
"@type": "Document",
"title": "Modified Page",
"review_state": "private"
},
{
"@id": "http://localhost:8080/plone/folder/existing-page",
"@type": "Document",
"title": "Existing Page",
"review_state": "published"
},
{
"@id": "http://localhost:8080/plone/folder/another-page",
"@type": "Document",
"title": "Another Page",
"review_state": "published"
}
]
}
EasyForm Integration¶
Form Schema Serialization¶
EasyForm objects include form field definitions and submission endpoint.
http
GET /Plone/contact-form HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET http://localhost:8080/Plone/contact-form -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/contact-form', headers={'Accept': 'application/json'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/plone/contact-form",
"@type": "EasyForm",
"title": "Contact Form",
"form_action": "http://localhost:8080/plone/contact-form/@submit",
"form_fields": [
{
"name": "form.widgets.name",
"type": "TextLine",
"title": "Name",
"description": "Your full name",
"required": true
},
{
"name": "form.widgets.email",
"type": "Email",
"title": "Email",
"description": "Your email address",
"required": true
},
{
"name": "form.widgets.subject",
"type": "Choice",
"title": "Subject",
"description": "Select a subject",
"required": true,
"items": [
{"token": "general", "title": "General Inquiry"},
{"token": "support", "title": "Technical Support"},
{"token": "sales", "title": "Sales"}
]
},
{
"name": "form.widgets.message",
"type": "Text",
"title": "Message",
"description": "Your message",
"required": true
}
]
}
Form Submission¶
Submit form data with automatic CSRF protection handling.
http
POST /Plone/contact-form/@submit HTTP/1.1
Host: localhost:8080
Accept: application/json
Content-Type: application/json
{
"form.widgets.name": "John Doe",
"form.widgets.email": "john@example.com",
"form.widgets.message": "Hello World"
}
curl
curl -i -X POST http://localhost:8080/Plone/contact-form/@submit -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"form.widgets.email": "john@example.com", "form.widgets.message": "Hello World", "form.widgets.name": "John Doe"}'
python-requests
requests.post('http://localhost:8080/Plone/contact-form/@submit', headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json={'form.widgets.email': 'john@example.com', 'form.widgets.message': 'Hello World', 'form.widgets.name': 'John Doe'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"success": true
}
Workflow Management¶
Direct State Setting¶
Set workflow state directly bypassing normal transitions, with security updates.
http
POST /Plone/my-content/@workflow-set-state/published HTTP/1.1
Host: localhost:8080
Accept: application/json
Content-Type: application/json
{
"comment": "Direct publication via API"
}
curl
curl -i -X POST http://localhost:8080/Plone/my-content/@workflow-set-state/published -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"comment": "Direct publication via API"}'
python-requests
requests.post('http://localhost:8080/Plone/my-content/@workflow-set-state/published', headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json={'comment': 'Direct publication via API'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"action": "set state",
"actor": "system",
"comment": "Direct publication via API",
"review_state": "published",
"time": "2023-09-16T10:30:00+00:00",
"title": "Published"
}
Principals Search¶
Enhanced User/Group Search¶
Principals search filters AuthenticatedUsers group for non-managers.
http
GET /Plone/@principals?search=admin HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET 'http://localhost:8080/Plone/@principals?search=admin' -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/@principals?search=admin', headers={'Accept': 'application/json'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/plone/@principals",
"items": [
{
"@id": "http://localhost:8080/plone/@principals/admin",
"@type": "user",
"description": "",
"email": "admin@example.com",
"fullname": "Administrator",
"home_page": null,
"id": "admin",
"location": "",
"portrait": null,
"roles": ["Manager"],
"username": "admin"
}
],
"items_total": 1
}
Relations¶
Enhanced Relations with Trash Filtering¶
Get object relations with trashed objects automatically filtered out.
http
GET /Plone/@relations?sources=%2FPlone%2Fpage1 HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET 'http://localhost:8080/Plone/@relations?sources=%2FPlone%2Fpage1' -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/@relations?sources=%2FPlone%2Fpage1', headers={'Accept': 'application/json'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"relatedItems": [
{
"source": {
"@id": "http://localhost:8080/plone/page1",
"@type": "Document",
"title": "Page 1",
"UID": "12345678-1234-1234-1234-123456789abc"
},
"target": {
"@id": "http://localhost:8080/plone/page2",
"@type": "Document",
"title": "Related Page 2",
"UID": "87654321-4321-4321-4321-cba987654321"
}
}
],
"backRelatedItems": [
{
"source": {
"@id": "http://localhost:8080/plone/page3",
"@type": "Document",
"title": "Page 3",
"UID": "abcdef12-3456-7890-abcd-ef1234567890"
},
"target": {
"@id": "http://localhost:8080/plone/page1",
"@type": "Document",
"title": "Page 1",
"UID": "12345678-1234-1234-1234-123456789abc"
}
}
]
}
Elasticsearch Integration (RESTAPI)¶
For the original Elasticsearch support, check collective.elasticsearch documentation.
7inOne enhances Elasticsearch integration with custom German text analysis, aggregations, suggestions, and raw query support.
Aggregations and suggestions can be configured through the Plone registry. Alternatively you can provide your own aggregations and suggestions in the query body using the @raw-es-search endpoint.
Enhanced Search with Aggregations¶
The @es-search endpoint provides Elasticsearch queries with faceted search capabilities and search suggestions.
http
GET /Plone/@es-search?SearchableText=content&portal_type=Document HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET 'http://localhost:8080/Plone/@es-search?SearchableText=content&portal_type=Document' -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/@es-search?SearchableText=content&portal_type=Document', headers={'Accept': 'application/json'})
Response includes standard search results plus elasticsearch-specific data:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/plone/@es-search?SearchableText=content&portal_type=Document",
"items": [
{
"@id": "http://localhost:8080/plone/document1",
"@type": "Document",
"title": "Content Document 1",
"description": "Document containing content",
"review_state": "published"
},
{
"@id": "http://localhost:8080/plone/document2",
"@type": "Document",
"title": "Another Content Document",
"description": "More content here",
"review_state": "published"
}
],
"items_total": 15,
"elasticsearch": {
"aggregations": {
"portal_type": {
"buckets": [
{"key": "Document", "doc_count": 12, "title": "Page"},
{"key": "News Item", "doc_count": 3, "title": "News Item"}
]
},
"review_state": {
"buckets": [
{"key": "published", "doc_count": 10, "title": "Published"},
{"key": "private", "doc_count": 5, "title": "Private"}
]
}
},
"original_aggregations": {
"portal_type": {
"buckets": [
{"key": "Document", "doc_count": 45, "title": "Page"},
{"key": "News Item", "doc_count": 12, "title": "News Item"},
{"key": "Folder", "doc_count": 8, "title": "Folder"}
]
}
},
"suggest": {
"content_suggest": [
{
"text": "content",
"options": [
{"text": "content management", "score": 0.8},
{"text": "content types", "score": 0.6}
]
}
]
}
}
}
Popular Searches¶
Get configured popular search terms for display in search interface.
http
GET /Plone/@popular-searches HTTP/1.1
Host: localhost:8080
Accept: application/json
curl
curl -i -X GET http://localhost:8080/Plone/@popular-searches -H "Accept: application/json"
python-requests
requests.get('http://localhost:8080/Plone/@popular-searches', headers={'Accept': 'application/json'})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:8080/plone/@popular-searches",
"items": [
{
"title": "documentation",
"@id": "http://localhost:8080/plone/@es-search?SearchableText=documentation"
},
{
"title": "user guide",
"@id": "http://localhost:8080/plone/@es-search?SearchableText=user guide"
},
{
"title": "API reference",
"@id": "http://localhost:8080/plone/@es-search?SearchableText=API reference"
}
]
}
Raw Elasticsearch Queries¶
Execute raw Elasticsearch queries with automatic security filtering applied.
http
POST /Plone/@raw-es-search HTTP/1.1
Host: localhost:8080
Accept: application/json
Content-Type: application/json
{
"query": {
"match": {
"SearchableText": "important content"
}
},
"aggs": {
"types": {
"terms": {
"field": "portal_type"
}
}
},
"size": 20,
"sort": ["_score", "sortable_title"]
}
curl
curl -i -X POST http://localhost:8080/Plone/@raw-es-search -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"aggs": {"types": {"terms": {"field": "portal_type"}}}, "query": {"match": {"SearchableText": "important content"}}, "size": 20, "sort": ["_score", "sortable_title"]}'
python-requests
requests.post('http://localhost:8080/Plone/@raw-es-search', headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json={'aggs': {'types': {'terms': {'field': 'portal_type'}}}, 'query': {'match': {'SearchableText': 'important content'}}, 'size': 20, 'sort': ['_score', 'sortable_title']})
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"hits": {
"total": {
"value": 42,
"relation": "eq"
},
"hits": [
{
"_score": 1.2345,
"_source": {
"path": "/plone/important-document",
"title": "Important Document",
"portal_type": "Document",
"SearchableText": "This document contains important content for users."
}
},
{
"_score": 1.1234,
"_source": {
"path": "/plone/content-guide",
"title": "Content Creation Guide",
"portal_type": "Document",
"SearchableText": "Guide for creating important content in the system."
}
}
]
},
"aggregations": {
"types": {
"buckets": [
{"key": "Document", "doc_count": 35},
{"key": "News Item", "doc_count": 5},
{"key": "Folder", "doc_count": 2}
]
}
}
}
German Text Analysis¶
Custom Elasticsearch mapping includes German text analyzer for improved search in German content.
Features: - German stopwords filtering - Applied to SearchableText, Title, Description, and content_title fields - Custom fields configurable via registry wcs.backend.search.custom_fields
Configuration via Registry¶
Elasticsearch behavior is configurable through Plone registry records:
wcs.backend.search.aggregations: Faceted search aggregations configuration
wcs.backend.search.suggest: Search suggestions configuration
wcs.backend.search.popular_searches: Popular search terms list
wcs.backend.search.custom_fields: Additional Elasticsearch field mappings