Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 132 additions & 4 deletions features/filter/filter_validation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ Feature: Validate filters based upon filter description

@createSchema
Scenario: Required filter should not throw an error if set
When I am on "/filter_validators?required=foo"
When I am on "/filter_validators?required=foo&required-allow-empty=&arrayRequired[foo]="
Then the response status code should be 200

When I am on "/filter_validators?required="
Then the response status code should be 200
Scenario: Required filter that does not allow empty value should throw an error if empty
When I am on "/filter_validators?required=&required-allow-empty=&arrayRequired[foo]="
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "required" does not allow empty value'

Scenario: Required filter should throw an error if not set
When I am on "/filter_validators"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "required" is required'
Then the JSON node "detail" should match '/^Query parameter "required" is required\nQuery parameter "required-allow-empty" is required$/'

Scenario: Required filter should not throw an error if set
When I am on "/array_filter_validators?arrayRequired[]=foo&indexedArrayRequired[foo]=foo"
Expand All @@ -37,3 +39,129 @@ Feature: Validate filters based upon filter description
When I am on "/array_filter_validators?arrayRequired[]=foo&indexedArrayRequired[bar]=bar"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "indexedArrayRequired[foo]" is required'

Scenario: Test filter bounds: maximum
When I am on "/filter_validators?required=foo&required-allow-empty&maximum=10"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&maximum=11"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "maximum" must be less than or equal to 10'

Scenario: Test filter bounds: exclusiveMaximum
When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMaximum=9"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMaximum=10"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "exclusiveMaximum" must be less than 10'

Scenario: Test filter bounds: minimum
When I am on "/filter_validators?required=foo&required-allow-empty&minimum=5"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&minimum=0"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "minimum" must be greater than or equal to 5'

Scenario: Test filter bounds: exclusiveMinimum
When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMinimum=6"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&exclusiveMinimum=5"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "exclusiveMinimum" must be greater than 5'

Scenario: Test filter bounds: max length
When I am on "/filter_validators?required=foo&required-allow-empty&max-length-3=123"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&max-length-3=1234"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "max-length-3" length must be lower than or equal to 3'

Scenario: Do not throw an error if value is not an array
When I am on "/filter_validators?required=foo&required-allow-empty&max-length-3[]=12345"
Then the response status code should be 200

Scenario: Test filter bounds: min length
When I am on "/filter_validators?required=foo&required-allow-empty&min-length-3=123"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&min-length-3=12"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "min-length-3" length must be greater than or equal to 3'

Scenario: Test filter pattern
When I am on "/filter_validators?required=foo&required-allow-empty&pattern=pattern"
When I am on "/filter_validators?required=foo&required-allow-empty&pattern=nrettap"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&pattern=not-pattern"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "pattern" must match pattern /^(pattern|nrettap)$/'

Scenario: Test filter enum
When I am on "/filter_validators?required=foo&required-allow-empty&enum=in-enum"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&enum=not-in-enum"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "enum" must be one of "in-enum, mune-ni"'

Scenario: Test filter multipleOf
When I am on "/filter_validators?required=foo&required-allow-empty&multiple-of=4"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&multiple-of=3"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "multiple-of" must multiple of 2'

Scenario: Test filter array items csv format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&csv-min-2=a,b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&csv-min-2=a"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "csv-min-2" must contain more than 2 values'

Scenario: Test filter array items csv format maxItems
When I am on "/filter_validators?required=foo&required-allow-empty&csv-max-3=a,b,c"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&csv-max-3=a,b,c,d"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "csv-max-3" must contain less than 3 values'

Scenario: Test filter array items tsv format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&tsv-min-2=a\tb"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&tsv-min-2=a,b"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "tsv-min-2" must contain more than 2 values'

Scenario: Test filter array items pipes format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&pipes-min-2=a|b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&pipes-min-2=a,b"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "pipes-min-2" must contain more than 2 values'

Scenario: Test filter array items ssv format minItems
When I am on "/filter_validators?required=foo&required-allow-empty&ssv-min-2=a b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&ssv-min-2=a,b"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "ssv-min-2" must contain more than 2 values'

@dropSchema
Scenario: Test filter array items unique items
When I am on "/filter_validators?required=foo&required-allow-empty&csv-uniques=a,b"
Then the response status code should be 200

When I am on "/filter_validators?required=foo&required-allow-empty&csv-uniques=a,a"
Then the response status code should be 400
And the JSON node "detail" should be equal to 'Query parameter "csv-uniques" must contain unique values'
8 changes: 6 additions & 2 deletions src/Bridge/Symfony/Bundle/Resources/config/validator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@
<tag name="kernel.event_listener" event="kernel.view" method="onKernelView" priority="64" />
</service>

<service id="api_platform.listener.view.validate_query_parameters" class="ApiPlatform\Core\Filter\QueryParameterValidateListener" public="false">
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<service id="api_platform.validator.query_parameter_validator" class="ApiPlatform\Core\Filter\QueryParameterValidator" public="false">
<argument type="service" id="api_platform.filter_locator" />
</service>

<service id="api_platform.listener.view.validate_query_parameters" class="ApiPlatform\Core\EventListener\QueryParameterValidateListener" public="false">
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<argument type="service" id="api_platform.validator.query_parameter_validator" />

<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="16" />
</service>
Expand Down
2 changes: 2 additions & 0 deletions src/Bridge/Symfony/Validator/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
* Validates an item using the Symfony validator component.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*
* @final
*/
class Validator implements ValidatorInterface
{
Expand Down
59 changes: 59 additions & 0 deletions src/EventListener/QueryParameterValidateListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Core\EventListener;

use ApiPlatform\Core\Filter\QueryParameterValidator;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Util\RequestAttributesExtractor;
use ApiPlatform\Core\Util\RequestParser;
use Symfony\Component\HttpKernel\Event\RequestEvent;

/**
* Validates query parameters depending on filter description.
*
* @author Julien Deniau <julien.deniau@mapado.com>
*/
final class QueryParameterValidateListener
{
private $resourceMetadataFactory;

private $queryParameterValidator;

public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, QueryParameterValidator $queryParameterValidator)
{
$this->resourceMetadataFactory = $resourceMetadataFactory;
$this->queryParameterValidator = $queryParameterValidator;
}

public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
if (
!$request->isMethodSafe()
|| !($attributes = RequestAttributesExtractor::extractAttributes($request))
|| !isset($attributes['collection_operation_name'])
|| !($operationName = $attributes['collection_operation_name'])
|| 'GET' !== $request->getMethod()
) {
return;
}
$queryString = RequestParser::getQueryString($request);
$queryParameters = $queryString ? RequestParser::parseRequestParams($queryString) : [];

$resourceMetadata = $this->resourceMetadataFactory->create($attributes['resource_class']);
$resourceFilters = $resourceMetadata->getCollectionOperationAttribute($operationName, 'filters', [], true);

$this->queryParameterValidator->validateFilters($attributes['resource_class'], $resourceFilters, $queryParameters);
}
}
104 changes: 0 additions & 104 deletions src/Filter/QueryParameterValidateListener.php

This file was deleted.

Loading