Skip to content

MapQueryString/MapRequestPayload skips validation when empty request is sent. #54617

@unixslayer

Description

@unixslayer

Symfony version(s) affected

6.4.6

Description

It seems to be impossible to validate request properly when sent empty. For both query string and request payload mapper will return null and skip validation. Using default value makes callable being called with object which may be invalid.

How to reproduce

final class ApiDTO
{
    #[Assert\NotBlank]
    public string $foo = '';
}
class FooController extends AbstractController
{
    #[Route("/foo", methods: ["GET"])]
    public function __invoke(#[MapQueryString(validationFailedStatusCode: 400)] ApiDTO $dto = new ApiDTO()): JsonResponse {
        dd($dto);
    }
}
expected behavior
GET /foo?foo= -> 400

validation skipped
GET /foo -> ApiDTO {
    +foo: ""
}

Possible Solution

Possible solution would be to make mapper method return default value if defined instead of returning null

// symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php:162
private function mapQueryString(Request $request, string $type, MapQueryString $attribute): ?object
{
    if (!$data = $request->query->all()) {
        return $attribute->metadata->hasDefaultValue() ? $attribute->metadata->getDefaultValue() : null;
    }

    return $this->serializer->denormalize($data, $type, null, $attribute->serializationContext + self::CONTEXT_DENORMALIZE);
}

// symfony/http-kernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php:185
if ('' === $data = $request->getContent()) {
    return $attribute->metadata->hasDefaultValue() ? $attribute->metadata->getDefaultValue() : null;
}
GET /foo?foo= -> 400
GET /foo -> 400

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions