Description
Symfony version(s) affected
7.0.0 RC1
Description
I am testing the new SF7 RC1 (can't confirm yet if this is the same behaviour we get on previous versions), and I have noticed that when I send an HTTP Request to my API endpoint (expecting a Request JSON Payload):
Postman
requests get a415 Unsupported Media Type
response, whileSymfony BrowserKit
viaPHPUnit
returns a422 Unprocessable Content
response
How to reproduce
I have created a DTO to map the Request Payload:
class CreateUserRequestDto
{
#[Assert\NotBlank(message: 'create_user__email__not_blank')]
#[Assert\Email(message: 'create_user__email__invalid', mode: 'strict')]
#[Assert\Length(max: 100, maxMessage: 'create_user__email__length')]
#[UniqueValue(class: UserEntity::class, field: 'email', message: 'create_user__email__unique')]
public ?string $email = null;
#[Assert\NotBlank(message: 'create_user__password__not_blank')]
public ?string $password = null;
#[Assert\NotBlank(message: 'create_user__nickname__not_blank')]
#[Assert\Length(max: 100, maxMessage: 'create_user__nickname__length')]
#[SerializedName(serializedName: 'public_name')]
public ?string $publicName = null;
#[Assert\NotBlank(message: 'create_user__preferred_currency__not_blank')]
#[Assert\Currency(message: 'create_user__preferred_currency__invalid')]
#[Assert\Choice(choices: ['EUR', 'USD'], message: 'create_user__preferred_currency__invalid')]
public ?string $currency = 'EUR';
#[Assert\NotBlank(message: 'create_user__date_of_birth__not_blank')]
#[Assert\Date(message: 'create_user__date_of_birth__invalid')]
public ?string $dob = null;
#[Assert\NotBlank(message: 'create_user__terms_of_service_acceptance__not_blank')]
#[Assert\IsTrue(message: 'create_user__terms_of_service_acceptance__invalid')]
#[SerializedName(serializedName: 'accept_tos')]
public bool $termsAcceptance = false;
}
And I have set the #[MapRequestPayload]
attribute as a prefix for this DTO:
// src/Controller/Anonymous/CreateUserController.php
class CreateUserController extends AbstractController
{
public function __construct(
private readonly EventDispatcherInterface $eventDispatcher,
private readonly SerializerInterface $serializer,
) {
}
#[Post(path: '/api/v3/users', name: 'api_v3_users_create')]
// RESPONSE: "201 Created" when successful
// RESPONSE: "415 Unsupported Media Type" when no JSON Payload is provided (according to Postman)
// RESPONSE: "422 Unprocessable Content" when JSON Payload is invalid (according to Postman & validation errors)
public function __invoke(#[MapRequestPayload] CreateUserRequestDto $requestDTO): JsonResponse
{
// Dispatch the required event
$event = $this->eventDispatcher->dispatch(
event: new CreateUserEvent(input: $requestDTO)
);
// Serialize the expected output
$data = $this->serializer->serialize(
data: $event->getOutput(),
format: 'json',
context: ['groups' => ['AtTag', 'MyUser']]
);
// Return the JSON response with the expected status code
return new JsonResponse(data: $data, status: Response::HTTP_CREATED, json: true);
}
}
My Postman request looks like this:
curl --location --request POST 'http://localhost:8080/api/v3/users' \
--data ''

And my test creates a client and calls the endpoint:
$httpClient = static::createClient();
$httpClient->request(
method: 'POST',
uri: '/api/v3/users',
server: ['CONTENT_TYPE' => 'application/json', 'HTTP_ACCEPT' => 'application/json'],
content: '', // setting an empty string to make it match with Postman's data
);
There was 1 failure:
1) App\Tests\Controller\Anonymous\CreateUserControllerTest::testCreateUserWithoutJsonPayload
Failed asserting that the Response status code is 415.
HTTP/1.1 422 Unprocessable Content
Cache-Control: no-cache, private
Content-Type: application/json
Date: Thu, 16 Nov 2023 13:30:35 GMT
X-Robots-Tag: noindex
{"code":422,"error":"Unprocessable Content","message":""}
/opt/project/vendor/symfony/framework-bundle/Test/BrowserKitAssertionsTrait.php:148
/opt/project/vendor/symfony/framework-bundle/Test/BrowserKitAssertionsTrait.php:38
/opt/project/tests/Controller/Anonymous/CreateUserControllerTest.php:23
/opt/project/vendor/phpunit/phpunit/phpunit:107
Possible Solution
Given I am setting an empty string (the same way that Postman / Curl seems to operate, I would expect to get a 415 Unsupported Media Type
error response, as this is the only way to keep consistency and make sure all the tests behave the same way we will respond to any developer using the API we are building.
Additional Context
I understand that the BrowserKit must run some check or processing that modifies the provided Request
content "as is"?
If so, should it pass the content as provided so the developer building the API keeps complete control?