diff --git a/docs/source/endpoints/querystringsearch.md b/docs/source/endpoints/querystringsearch.md
index 953348f4ec..7cc5666636 100644
--- a/docs/source/endpoints/querystringsearch.md
+++ b/docs/source/endpoints/querystringsearch.md
@@ -11,7 +11,9 @@ myst:
The `@querystring-search` endpoint returns search results that can be filtered on search criteria.
-Call the `/@querystring-search` endpoint with a `POST` request and a query in the request body:
+Call the `/@querystring-search` endpoint with either a `POST` or `GET` request.
+
+When using the `POST` request, provide a query in the request body:
```{eval-rst}
.. http:example:: curl httpie python-requests
@@ -24,6 +26,19 @@ The server will respond with the results that are filtered based on the query yo
:language: http
```
+When using the `GET` request, provide the query as a JSON URL-encoded string as a parameter.
+
+```{eval-rst}
+.. http:example:: curl httpie python-requests
+ :request: ../../../src/plone/restapi/tests/http-examples/querystringsearch_get.req
+```
+
+The server will respond with the results that are filtered based on the query you provided:
+
+```{literalinclude} ../../../src/plone/restapi/tests/http-examples/querystringsearch_get.resp
+:language: http
+```
+
Parameters the endpoint will accept:
- `query` - `plone.app.querystring` query, required
@@ -34,10 +49,8 @@ Parameters the endpoint will accept:
- `limit` - integer, limits the number of returned results
- `fullobjects` - boolean, if `true` then return the full objects instead of just the summary serialization
-
## Parameters
-
### Batch Start (`b_start`)
The `b_start` parameter defines the first item of the batch:
@@ -58,7 +71,6 @@ The `b_start` parameter defines the first item of the batch:
The `b_size` parameter is optional.
The default value is `0`.
-
### Batch Size (b_size)
The `b_size` parameter defines the number of elements a single batch returns:
@@ -79,7 +91,6 @@ The `b_size` parameter defines the number of elements a single batch returns:
The parameter is optional.
The default value is `25`.
-
### Sort on
The `sort_on` parameter defines the field that is used to sort the returned search results:
@@ -100,7 +111,6 @@ The `sort_on` parameter defines the field that is used to sort the returned sear
The `sort_on` parameter is optional.
The default value is `None`.
-
### Sort Order
The `sort_order` parameter defines the sort order when the `sort_on` field has been set:
@@ -126,7 +136,6 @@ The sort_order can be either `ascending` or `descending`.
`ascending` means from A to Z for a text field.
`reverse` is an alias equivalent to `descending`.
-
### Limit
Querystring `query` with a `limit` parameter:
@@ -147,7 +156,6 @@ Querystring `query` with a `limit` parameter:
The `limit` parameter is optional.
The default value is `1000`.
-
### Query
The `query` parameter is a list that contains an arbitrary number of `filters`:
@@ -176,10 +184,8 @@ The following types of filters are available:
- Date filters
- Text Filters
-
#### Metadata Filters
-
##### Creator
The `creator` of the content object.
@@ -212,7 +218,6 @@ You can either set the currently logged in user:
}
```
-
##### Shortname
`Shortname` is the ID of the object that is shown as the last part of the URL:
@@ -229,7 +234,6 @@ You can either set the currently logged in user:
}
```
-
##### Location
`Location` is the path of the content object on the site.
@@ -305,7 +309,6 @@ The path can contain a depth parameter that is separated with `::`:
}
```
-
##### Type
Filter by portal type:
@@ -322,7 +325,6 @@ Filter by portal type:
}
```
-
##### Review State
Filter results by review state:
@@ -339,7 +341,6 @@ Filter results by review state:
}
```
-
##### Show Inactive
Show inactive will return content objects that is expired for a given role:
@@ -356,10 +357,8 @@ Show inactive will return content objects that is expired for a given role:
}
```
-
#### Text Filters
-
##### Description
Filter content that contains a term in the Description field:
@@ -376,7 +375,6 @@ Filter content that contains a term in the Description field:
}
```
-
##### Searchable Text
Filter content that contains a term in the SearchableText (all searchable fields in the catalog):
@@ -393,7 +391,6 @@ Filter content that contains a term in the SearchableText (all searchable fields
}
```
-
##### Tag
Filter by a tag (subjects field):
@@ -410,7 +407,6 @@ Filter by a tag (subjects field):
}
```
-
##### Title
Filter by exact Title match:
@@ -425,10 +421,8 @@ Filter by exact Title match:
]
```
-
#### Date Filters
-
##### Creation Date
Filter by creation date:
@@ -445,7 +439,6 @@ Filter by creation date:
}
```
-
##### Effective Date
Filter by effective date:
@@ -463,7 +456,6 @@ Filter by effective date:
}
```
-
##### Event end date
Filter by event end date:
@@ -480,7 +472,6 @@ Filter by event end date:
}
```
-
##### Event start date
Filter by event start date:
@@ -497,7 +488,6 @@ Filter by event start date:
}
```
-
##### Expiration date
Filter by expiration date:
@@ -515,7 +505,6 @@ Filter by expiration date:
}
```
-
##### Modification date
Filter by modification date:
diff --git a/news/1616.feature b/news/1616.feature
new file mode 100644
index 0000000000..be2a4c579f
--- /dev/null
+++ b/news/1616.feature
@@ -0,0 +1 @@
+Add querystring_search get method. @robgietema
diff --git a/src/plone/restapi/services/querystringsearch/configure.zcml b/src/plone/restapi/services/querystringsearch/configure.zcml
index 9a7ad20595..899f1f1156 100644
--- a/src/plone/restapi/services/querystringsearch/configure.zcml
+++ b/src/plone/restapi/services/querystringsearch/configure.zcml
@@ -18,4 +18,20 @@
permission="zope2.View"
name="@querystring-search"
/>
+
+
+
+
diff --git a/src/plone/restapi/services/querystringsearch/get.py b/src/plone/restapi/services/querystringsearch/get.py
index 29ed3f9471..79de69accd 100644
--- a/src/plone/restapi/services/querystringsearch/get.py
+++ b/src/plone/restapi/services/querystringsearch/get.py
@@ -4,8 +4,11 @@
from plone.restapi.deserializer import json_body
from plone.restapi.interfaces import ISerializeToJson
from plone.restapi.services import Service
+from urllib import parse
from zope.component import getMultiAdapter
+import json
+
zcatalog_version = get_distribution("Products.ZCatalog").version
if parse_version(zcatalog_version) >= parse_version("5.1"):
@@ -14,11 +17,14 @@
SUPPORT_NOT_UUID_QUERIES = False
-class QuerystringSearchPost(Service):
+class QuerystringSearch:
"""Returns the querystring search results given a p.a.querystring data."""
- def reply(self):
- data = json_body(self.request)
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self, data):
query = data.get("query", None)
b_start = int(data.get("b_start", 0))
b_size = int(data.get("b_size", 25))
@@ -60,3 +66,21 @@ def reply(self):
fullobjects=fullobjects
)
return results
+
+
+class QuerystringSearchPost(Service):
+ """Returns the querystring search results given a p.a.querystring data."""
+
+ def reply(self):
+ querystring_search = QuerystringSearch(self.context, self.request)
+ return querystring_search(data=json_body(self.request))
+
+
+class QuerystringSearchGet(Service):
+ """Returns the querystring search results given a p.a.querystring data."""
+
+ def reply(self):
+ querystring_search = QuerystringSearch(self.context, self.request)
+ return querystring_search(
+ data=json.loads(parse.unquote(self.request.form.get("query", "{}")))
+ )
diff --git a/src/plone/restapi/tests/http-examples/querystringsearch_get.req b/src/plone/restapi/tests/http-examples/querystringsearch_get.req
new file mode 100644
index 0000000000..0f859a5cc5
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/querystringsearch_get.req
@@ -0,0 +1,3 @@
+GET /plone/@querystring-search?query=%257B%2522query%2522%253A%255B%257B%2522i%2522%253A%2522portal_type%2522%252C%2522o%2522%253A%2520%2522plone.app.querystring.operation.selection.any%2522%252C%2522v%2522%253A%255B%2522Document%2522%255D%257D%255D%257D HTTP/1.1
+Accept: application/json
+Authorization: Basic YWRtaW46c2VjcmV0
diff --git a/src/plone/restapi/tests/http-examples/querystringsearch_get.resp b/src/plone/restapi/tests/http-examples/querystringsearch_get.resp
new file mode 100644
index 0000000000..780f8f4ee7
--- /dev/null
+++ b/src/plone/restapi/tests/http-examples/querystringsearch_get.resp
@@ -0,0 +1,23 @@
+HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+ "@id": "http://localhost:55001/plone/@querystring-search?query=%257B%2522query%2522%253A%255B%257B%2522i%2522%253A%2522portal_type%2522%252C%2522o%2522%253A%2520%2522plone.app.querystring.operation.selection.any%2522%252C%2522v%2522%253A%255B%2522Document%2522%255D%257D%255D%257D",
+ "items": [
+ {
+ "@id": "http://localhost:55001/plone/front-page",
+ "@type": "Document",
+ "description": "Congratulations! You have successfully installed Plone.",
+ "review_state": "private",
+ "title": "Welcome to Plone"
+ },
+ {
+ "@id": "http://localhost:55001/plone/testdocument",
+ "@type": "Document",
+ "description": "",
+ "review_state": "private",
+ "title": "Test Document"
+ }
+ ],
+ "items_total": 2
+}
diff --git a/src/plone/restapi/tests/test_documentation.py b/src/plone/restapi/tests/test_documentation.py
index 6e8b88ded7..2103b1e2e3 100644
--- a/src/plone/restapi/tests/test_documentation.py
+++ b/src/plone/restapi/tests/test_documentation.py
@@ -1686,6 +1686,18 @@ def test_querystringsearch_post(self):
)
save_request_and_response_for_docs("querystringsearch_post", response)
+ def test_querystringsearch_get(self):
+ query = {
+ "query": "%7B%22query%22%3A%5B%7B%22i%22%3A%22portal_type%22%2C%22o%22%3A%20%22plone.app.querystring.operation.selection.any%22%2C%22v%22%3A%5B%22Document%22%5D%7D%5D%7D"
+ }
+ url = "/@querystring-search"
+
+ self.portal.invokeFactory("Document", "testdocument", title="Test Document")
+ transaction.commit()
+
+ response = self.api_session.get(url, params=query)
+ save_request_and_response_for_docs("querystringsearch_get", response)
+
def test_system_get(self):
response = self.api_session.get("/@system")
save_request_for_docs("system_get", response)
diff --git a/src/plone/restapi/tests/test_services_querystringsearch.py b/src/plone/restapi/tests/test_services_querystringsearch.py
index 8dd77f7dc6..69f777a3bd 100644
--- a/src/plone/restapi/tests/test_services_querystringsearch.py
+++ b/src/plone/restapi/tests/test_services_querystringsearch.py
@@ -52,6 +52,18 @@ def test_querystringsearch_basic(self):
self.assertEqual(len(response.json()["items"]), 1)
self.assertNotIn("effective", response.json()["items"][0])
+ def test_querystringsearch_basic_get(self):
+ response = self.api_session.get(
+ "/@querystring-search?query=%7B%22query%22%3A%5B%7B%22i%22%3A%22portal_type%22%2C%22o%22%3A%20%22plone.app.querystring.operation.selection.any%22%2C%22v%22%3A%5B%22Document%22%5D%7D%5D%7D"
+ )
+
+ self.assertEqual(response.status_code, 200)
+ self.assertIn("items", response.json())
+ self.assertIn("items_total", response.json())
+ self.assertEqual(response.json()["items_total"], 1)
+ self.assertEqual(len(response.json()["items"]), 1)
+ self.assertNotIn("effective", response.json()["items"][0])
+
def test_querystringsearch_fullobjects(self):
response = self.api_session.post(
"/@querystring-search",