From a36bef3db1a17e9da7deb96e1f2ffb8cc6ee428a Mon Sep 17 00:00:00 2001 From: soyuka Date: Fri, 11 Sep 2026 23:23:12 +0200 Subject: [PATCH 1/3] docs(core): document HTTP QUERY operation --- core/operations.md | 120 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/core/operations.md b/core/operations.md index 6239007ca39..0f6ba92114f 100644 --- a/core/operations.md +++ b/core/operations.md @@ -48,6 +48,126 @@ Item operations: | `PATCH` | no | Apply a partial modification to an element | yes | | `DELETE` | no | Delete an element | yes | +## The HTTP QUERY Operation + +[HTTP QUERY](https://www.rfc-editor.org/rfc/rfc10008.html) is a safe, idempotent collection +operation whose criteria are sent in the request body instead of the URI. It is useful when a +collection query is too large or too structured for a URL. API Platform does not enable it by +default; add a `Query` operation explicitly. + +Unlike `GET`, a `QUERY` request must include a `Content-Type` header, including when its body is +empty. API Platform supports `application/json` and `application/x-www-form-urlencoded` request +bodies for this operation. + +The following operation uses a parameter-driven filter. Although it is declared with +`QueryParameter`, the `name` criterion is sent in the `QUERY` request body, not as +`?name=...` in the URL: + +```php + new QueryParameter( + filter: new PartialSearchFilter(), + property: 'name', + ), + ]), +])] +class Book +{ + // ... +} +``` + +Call the `QUERY` operation with the same collection URI: + +```console +curl -X QUERY https://example.com/books \ + -H 'Accept: application/ld+json' \ + -H 'Content-Type: application/json' \ + --data '{"name":"Dune"}' +``` + +The parsed values are processed by the same [parameter and filter system](filters.md) as URL query +parameters. This lets existing `QueryParameter` filters describe and apply body criteria without a +custom provider. + +### Criteria DTOs + +For a structured query, set an `input` class on the operation and put `QueryParameter` attributes +on its properties. API Platform uses that class as the request-body schema and discovers its +parameters to apply their filters: + +```php + [!NOTE] The `PATCH` method must be enabled explicitly in the configuration, refer to the > [Content Negotiation](content-negotiation.md) section for more information. From df49398e29b19f85038f044f68fed683bbd162dc Mon Sep 17 00:00:00 2001 From: soyuka Date: Sat, 12 Sep 2026 07:27:31 +0200 Subject: [PATCH 2/3] docs(core): add QUERY processor example --- core/operations.md | 69 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/core/operations.md b/core/operations.md index 0f6ba92114f..c5c6edadede 100644 --- a/core/operations.md +++ b/core/operations.md @@ -60,8 +60,8 @@ empty. API Platform supports `application/json` and `application/x-www-form-urle bodies for this operation. The following operation uses a parameter-driven filter. Although it is declared with -`QueryParameter`, the `name` criterion is sent in the `QUERY` request body, not as -`?name=...` in the URL: +`QueryParameter`, the `name` criterion is sent in the `QUERY` request body, not as `?name=...` in +the URL: ```php > */ +final readonly class BookCriteriaProcessor implements ProcessorInterface +{ + public function __construct(private BookSearch $bookSearch) {} + + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): iterable + { + if (!$data instanceof BookCriteria) { + throw new \LogicException('Expected BookCriteria.'); + } + + return $this->bookSearch->search($data); + } +} ``` This is the processor path: a processor is only called for a safe operation when `write` is set to From ad479e94bcd18ff1c35554b7cd0db9db5bbac8a3 Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Sat, 12 Sep 2026 07:33:53 +0200 Subject: [PATCH 3/3] Apply suggestion from @soyuka --- core/operations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/operations.md b/core/operations.md index c5c6edadede..780114e47f4 100644 --- a/core/operations.md +++ b/core/operations.md @@ -190,7 +190,7 @@ final readonly class BookCriteriaProcessor implements ProcessorInterface public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): iterable { if (!$data instanceof BookCriteria) { - throw new \LogicException('Expected BookCriteria.'); + throw new \RutimeException('Expected BookCriteria.'); } return $this->bookSearch->search($data);