Ctrl+K
Logo image

Table of Contents

  • Introduction
  • Usage
    • Authentication
    • Batching
    • Content Manipulation
    • Customizing the API
    • Explore the API using Postman
    • i18n: internationalization of screen messages
    • Serialization
    • Sharing
    • Types Schema
    • Volto Blocks support
  • Endpoints
    • Add-ons
    • Aliases
    • Breadcrumbs
    • Comments
    • Content Types
    • Content Rules
    • Context Navigation
    • Control Panels
    • Copy and Move
    • Database
    • Email Notification
    • Email Send
    • Expansion
    • Groups
    • History
    • Link Integrity
    • Locking
    • Navigation
    • Portal Actions
    • Portraits
    • Principals
    • Querystring
    • Querystring Search
    • Registry
    • Roles
    • Search
    • System
    • Tiles
    • Transactions
    • Translations
    • TUS resumable upload
    • Types
    • Upgrade
    • Users
    • User schema
    • Vocabularies and Sources
    • Workflow
    • Working Copy
  • Upgrade Guide
  • Contributing to plone.restapi
    • Conventions
  • HTTP Status Codes
  • Glossary
  • Repository
  • Suggest edit
  • Open issue
  • .md

Search

Contents

  • Query format
    • Query options
    • Restricting search to multiple paths
    • Sorting on multiple indexes
    • Data types in queries
  • Retrieving additional metadata
  • Retrieving full objects
  • Restrict search results to Plone's search settings

Search#

Content in a Plone site can be searched for by invoking the /@search endpoint in any context:

GET /plone/@search HTTP/1.1
Accept: application/json

A search is contextual by default. In other words, it is bound to a specific context—a collection in HTTP REST terms—and searches within that collection and any sub-collections.

A Plone site is also a collection. We therefore have a global search by invoking the /@search endpoint on the site root. We also have contextual searches by invoking that endpoint on any other context. All searches use the same pattern.

In terms of the resulting catalog query, this means that, by default, a search will be constrained by the path to the context on which it is invoked, unless you explicitly supply your own path query.

Search results are represented similar to collections:

http

GET /plone/@search?sort_on=path HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET 'http://nohost/plone/@search?sort_on=path' -H "Accept: application/json" --user admin:secret

httpie

http 'http://nohost/plone/@search?sort_on=path' Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@search?sort_on=path', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "@id": "http://localhost:55001/plone/@search",
    "items": [
        {
            "@id": "http://localhost:55001/plone",
            "@type": "Plone Site",
            "description": "",
            "review_state": null,
            "title": "Plone site"
        },
        {
            "@id": "http://localhost:55001/plone/front-page",
            "@type": "Document",
            "description": "Congratulations! You have successfully installed Plone.",
            "review_state": "private",
            "title": "Welcome to Plone"
        }
    ],
    "items_total": 2
}

The default representation for search results is a summary that contains only the most basic information. In order to return specific metadata columns, see the documentation of the metadata_fields parameter below.

Note

A search invoked on a container will by default include that container itself as part of the search results. This is the same behavior as displayed by ZCatalog, which is used internally. If you add the query string parameter path.depth=1 to your search, you will only get the immediate children of the container, and the container itself won't be part of the results. See the Plone documentation on searching for content within a folder for more details.

Note

Search results will be batched if the size of the resultset exceeds the batch size. See Batching for more details on how to work with batched results.

Warning

The @@search view or the Plone LiveSearch widget are coded in a way that the SearchableText parameter is expanded by including a * wildcard at the end. This is done to also match the partial results of the beginning of search terms. The plone.restapi @search endpoint will not do that for you. You will have to add it if you want to keep this feature.

Query format#

Queries and query-wide options, such as sort_on, are submitted as query string parameters to the /@search request:

GET /plone/@search?SearchableText=lorem HTTP/1.1

This is nearly identical to the way that queries are passed to the Plone @@search browser view, with only a few minor differences.

For general information on how to query the Plone catalog, please refer to the Plone Documentation on Querying.

Query options#

In case you want to supply query options to a query against a particular index, you will need to flatten the corresponding query dictionary and use a dotted notation to indicate nesting.

For example, to specify the depth query option for a path query, the original query as a Python dictionary would look like this:

query = {"path": {"query": "/folder1",
                  "depth": 2}}

This dictionary will need to be flattened in dotted notation to pass it into a query string:

http

GET /plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.depth=1 HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET 'http://nohost/plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.depth=1' -H "Accept: application/json" --user admin:secret

httpie

http 'http://nohost/plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.depth=1' Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.depth=1', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "@id": "http://localhost:55001/plone/@search?path.query=%2Fplone%2Ffolder1&path.depth=1",
    "items": [
        {
            "@id": "http://localhost:55001/plone/folder1/folder2",
            "@type": "Folder",
            "description": "",
            "review_state": "private",
            "title": "Folder 2"
        }
    ],
    "items_total": 1
}

Again this is very similar to how Record Arguments are parsed by ZPublisher, except that you can omit the :record suffix.

Restricting search to multiple paths#

To restrict a search to multiple paths, the original query as a Python dictionary would look like this, with an optional depth and sort_on:

query = {"path": {"query": ("/folder", "/folder2"),
                  "depth": 2},
         "sort_on": "path"}

This dictionary will need to be flattened in dotted notation to pass it into a query string. To specify multiple paths, repeat the query string parameter. The requests module will automatically do this for you if you pass it a list of values for a query string parameter.

http

GET /plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.query=%2Fplone%2Ffolder2&path.depth=2 HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET 'http://nohost/plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.query=%2Fplone%2Ffolder2&path.depth=2' -H "Accept: application/json" --user admin:secret

httpie

http 'http://nohost/plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.query=%2Fplone%2Ffolder2&path.depth=2' Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@search?sort_on=path&path.query=%2Fplone%2Ffolder1&path.query=%2Fplone%2Ffolder2&path.depth=2', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "@id": "http://localhost:55001/plone/@search?path.query=%2Fplone%2Ffolder1&path.query=%2Fplone%2Ffolder2&path.depth=2",
    "items": [
        {
            "@id": "http://localhost:55001/plone/folder1",
            "@type": "Folder",
            "description": "",
            "review_state": "private",
            "title": "Folder 1"
        },
        {
            "@id": "http://localhost:55001/plone/folder1/doc1",
            "@type": "Document",
            "description": "",
            "review_state": "private",
            "title": "Lorem Ipsum"
        },
        {
            "@id": "http://localhost:55001/plone/folder2",
            "@type": "Folder",
            "description": "",
            "review_state": "private",
            "title": "Folder 2"
        },
        {
            "@id": "http://localhost:55001/plone/folder2/doc2",
            "@type": "Document",
            "description": "",
            "review_state": "private",
            "title": "Lorem Ipsum"
        }
    ],
    "items_total": 4
}

Sorting on multiple indexes#

Sorting can happen on multiple indexes, as the underlying catalog supports it. To do so the query has to contain the list of indexes to be used for sorting in the sort_on parameter. If wanted the ordering of the sorting can also be added in the query in the sort_order parameter.

http

GET /plone/@search?sort_on=portal_type&sort_on=sortable_title HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET 'http://nohost/plone/@search?sort_on=portal_type&sort_on=sortable_title' -H "Accept: application/json" --user admin:secret

httpie

http 'http://nohost/plone/@search?sort_on=portal_type&sort_on=sortable_title' Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@search?sort_on=portal_type&sort_on=sortable_title', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))

Data types in queries#

Because HTTP query strings contain no information about data types, any query string parameter value ends up as a string in the Zope request. This means that for value types that are not strings, these data types need to be reconstructed on the server side in plone.restapi.

For most index types, their query values, and query options, plone.restapi can handle this for you. If you pass it path.query=foo&path.depth=1, it has the necessary knowledge about the ExtendedPathIndex's options to turn the string 1 for the depth argument back into an integer before passing the query on to the catalog.

However, certain index types, such as a FieldIndex, may take arbitrary data types as query values. In that case, plone.restapi cannot know to what data type to cast your query value. You will need to specify it using ZPublisher type hints:

GET /plone/@search?numeric_field:int=42 HTTP/1.1
Accept: application/json

Please refer to the Documentation on Argument Conversion in ZPublisher for details.

Retrieving additional metadata#

By default, the results are represented as summaries that contain only the most basic information about the items, such as their URL and title. If you need to retrieve additional metadata columns, you can do so by specifying the additional column names in the metadata_fields parameter:

http

GET /plone/@search?SearchableText=lorem&metadata_fields=modified&metadata_fields=created HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET 'http://nohost/plone/@search?SearchableText=lorem&metadata_fields=modified&metadata_fields=created' -H "Accept: application/json" --user admin:secret

httpie

http 'http://nohost/plone/@search?SearchableText=lorem&metadata_fields=modified&metadata_fields=created' Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@search?SearchableText=lorem&metadata_fields=modified&metadata_fields=created', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "@id": "http://localhost:55001/plone/@search?SearchableText=lorem&metadata_fields=modified&metadata_fields=created",
    "items": [
        {
            "@id": "http://localhost:55001/plone/doc1",
            "@type": "Document",
            "created": "1995-07-31T13:45:00",
            "description": "",
            "modified": "1995-07-31T17:30:00",
            "review_state": "private",
            "title": "Lorem Ipsum"
        }
    ],
    "items_total": 1
}

The metadata from those columns will then be included in the results. To specify multiple columns, repeat the query string parameter once for every column name. The requests module will automatically do this for you if you pass it a list of values for a query string parameter.

To retrieve all metadata columns that the catalog knows about, use metadata_fields=_all.

Note

There is a difference between the full set of fields contained in an object and the set of all possible metadata columns that can be specified with metadata_fields. In other words, using metadata_fields=_all will produce objects with a set of fields that is generally smaller than the set of fields produced by fullobjects (see next section). Briefly, the fields in metadata_fields=_all are a subset of fullobjects. A consequence of this is that certain fields can not be specifed with metadata_fields. Doing so will result in a TypeError "No converter for making <...> JSON compatible." In ZCatalog terms, this reflects the difference between catalog brains and objects that have been woken up.

Retrieving full objects#

If the data provided as metadata is not enough, you can retrieve search results as full serialized objects equivalent to what the resource GET request would produce.

You do so by specifying the fullobjects parameter:

http

GET /plone/@search?SearchableText=lorem&fullobjects=1 HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET 'http://nohost/plone/@search?SearchableText=lorem&fullobjects=1' -H "Accept: application/json" --user admin:secret

httpie

http 'http://nohost/plone/@search?SearchableText=lorem&fullobjects=1' Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@search?SearchableText=lorem&fullobjects=1', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "@id": "http://localhost:55001/plone/@search?SearchableText=lorem&fullobjects=1",
    "items": [
        {
            "@components": {
                "actions": {
                    "@id": "http://localhost:55001/plone/doc1/@actions"
                },
                "aliases": {
                    "@id": "http://localhost:55001/plone/doc1/@aliases"
                },
                "breadcrumbs": {
                    "@id": "http://localhost:55001/plone/doc1/@breadcrumbs"
                },
                "contextnavigation": {
                    "@id": "http://localhost:55001/plone/doc1/@contextnavigation"
                },
                "navigation": {
                    "@id": "http://localhost:55001/plone/doc1/@navigation"
                },
                "types": {
                    "@id": "http://localhost:55001/plone/doc1/@types"
                },
                "workflow": {
                    "@id": "http://localhost:55001/plone/doc1/@workflow"
                }
            },
            "@id": "http://localhost:55001/plone/doc1",
            "@type": "Document",
            "UID": "SomeUUID000000000000000000000002",
            "allow_discussion": false,
            "changeNote": "",
            "contributors": [],
            "created": "1995-07-31T13:45:00",
            "creators": [
                "test_user_1_"
            ],
            "description": "",
            "effective": null,
            "exclude_from_nav": false,
            "expires": null,
            "id": "doc1",
            "is_folderish": false,
            "language": "",
            "layout": "document_view",
            "lock": {
                "locked": false,
                "stealable": true
            },
            "modified": "1995-07-31T17:30:00",
            "next_item": {},
            "parent": {
                "@id": "http://localhost:55001/plone",
                "@type": "Plone Site",
                "description": "",
                "title": "Plone site"
            },
            "previous_item": {
                "@id": "http://localhost:55001/plone/front-page",
                "@type": "Document",
                "description": "Congratulations! You have successfully installed Plone.",
                "title": "Welcome to Plone"
            },
            "relatedItems": [],
            "review_state": "private",
            "rights": "",
            "subjects": [],
            "table_of_contents": null,
            "text": null,
            "title": "Lorem Ipsum",
            "version": "current",
            "versioning_enabled": true,
            "working_copy": null,
            "working_copy_of": null
        }
    ],
    "items_total": 1
}

Warning

Be aware that this might induce performance issues when retrieving a lot of resources. Normally the search just serializes catalog brains, but with fullobjects, we wake up all the returned objects.

Restrict search results to Plone's search settings#

By default, the search endpoint does not exclude any types from its results. To allow the search to follow Plone's search settings schema, pass the use_site_search_settings=1 to the @search endpoint request. By doing this, the search results will be filtered based on the defined types to be searched, and will be sorted according to the default sorting order.

previous

Roles

next

System

Contents
  • Query format
    • Query options
    • Restricting search to multiple paths
    • Sorting on multiple indexes
    • Data types in queries
  • Retrieving additional metadata
  • Retrieving full objects
  • Restrict search results to Plone's search settings

© Copyright 2014-2023, Plone Foundation.

The text and illustrations in this website are licensed by the Plone Foundation under a Creative Commons Attribution 4.0 International license. Plone and the Plone® logo are registered trademarks of the Plone Foundation, registered in the United States and other countries. For guidelines on the permitted uses of the Plone trademarks, see https://plone.org/foundation/logo. All other trademarks are owned by their respective owners.

Deploys by Netlify