Can't handling errors with Api-Platform

44 Views Asked by At

In my API-Platform (v 3.2/ Symfony 6.4) I'm trying to understand an error only on POST requests and only on prod environment. In development mode everything is OK and POST new users adding data in postgresq database. Here's my entity :

#[ORM\Entity(repositoryClass: ApiUserRepository::class)]
#[UniqueEntity('`email`')]
#[ApiResource(
    operations: [
        new GetCollection(
            description: "List of users",
            security: "is_granted('ROLE_ADMIN')"
        ),
        new Post(
            description: "Create new user",
            // security: "is_granted('ROLE_ADMIN')",
            validationContext: ['groups' => ['user:create']],
            processor: UserPasswordHasher::class
        )
    ],
    normalizationContext: ['groups' => ['user:read']],
    denormalizationContext: ['groups' => ['user:create']]
)]
class ApiUser implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\Column(type: 'uuid', unique: true)]
    #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
    private ?Uuid $id = null;

    #[Assert\Email(message: 'api_users.email.email', groups: ['user:create'])]
    #[Assert\NotBlank(message: 'api_users.email.not_blank', groups: ['user:create'])]
    #[Groups(['user:read', 'user:create'])]
    #[ORM\Column(length: 180, unique: true)]
    private ?string $email = null;

    #[ORM\Column(type: 'json')]
    private array $roles = [];

    #[ORM\Column]
    private ?string $password = null;

    #[Assert\NotBlank(message: 'api_users.plain_password.not_blank', groups: ['user:create'])]
    #[Assert\NotCompromisedPassword(message: 'api_users.plain_password.not_compromised', groups: ['user:create'])]
    #[Groups(['user:create'])]
    private ?string $plainPassword = null;

    // getters and setters
}

security is disabled for test. My UserPasswordHasher who encode password :

final readonly class UserPasswordHasher implements ProcessorInterface
{
    public function __construct(
        private ProcessorInterface          $processor,
        private UserPasswordHasherInterface $passwordHasher
    ) { }

    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ApiUser|null
    {
        if (!$data->getPlainPassword()) {
            return $this->processor->process($data, $operation, $uriVariables, $context);
        }

        $hashedPassword = $this->passwordHasher->hashPassword(
            $data,
            $data->getPlainPassword()
        );
        $data->setPassword($hashedPassword);
        $data->setIsActive(false);
        $data->setRoles(['ROLE_USER']);
        $data->eraseCredentials();
        return $this->processor->process($data, $operation, $uriVariables, $context);
    }
}

and definition in services.yaml

    App\State\UserPasswordHasher:
        bind:
            $processor: '@api_platform.doctrine.orm.state.persist_processor'

I'm trying posting good and bad data (for testing assertions). In dev mode :

# request
curl -k -L 'http://localhost/v2/api_users?pretty=true' -H 'Content-Type: application/ld+json' -d '{"email": "notAnEmail#gmail*com","plainPassword": "admin123"}'

# response 
{"@id":"\/v2\/validation_errors\/0=bd79c0ab-ddba-46cc-a703-a7a4b08de310;1=d9bcdbfe-a9d6-4bfa-a8ff-da5fd93e0f6d","@type":"ConstraintViolationList","status":422,"violations":[{"propertyPath":"email","message":"Please pick a valid email","code":"bd79c0ab-ddba-46cc-a703-a7a4b08de310"},{"propertyPath":"plainPassword","message":"Password too weak, please make it stronger","code":"d9bcdbfe-a9d6-4bfa-a8ff-da5fd93e0f6d"}],"detail":"email: Please pick a valid email\nplainPassword: Password too weak, please make it stronger","hydra:title":"An error occurred","hydra:description":"email: Please pick a valid email\nplainPassword: Password too weak, please make it stronger","type":"\/validation_errors\/0=bd79c0ab-ddba-46cc-a703-a7a4b08de310;1=d9bcdbfe-a9d6-4bfa-a8ff-da5fd93e0f6d","title":"An error occurred"}

# It's OK
# Same request with good data insert into database.

In production :

# bad request
curl -k -L 'https://api.mysite.com/v2/api_users' -H 'Content-Type: application/ld+json' -d '{"email": "notAnEmail#gmail*com","plainPassword": "admin123"}'
# good request
curl -k -L 'https://api.mysite.com/v2/api_users' -H 'Content-Type: application/ld+json' -d '{"email": "[email protected]","plainPassword": "V3r|Str0NgPwD#"}'

# same response with HTTP code 500
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="robots" content="noindex,nofollow,noarchive" />
    <title>An Error Occurred: Internal Server Error</title>
</head>
<body>
<div class="container">
    <h1>Oops! An Error Occurred</h1>
    <h2>The server returned a "500 Internal Server Error".</h2>

    <p>
        Something is broken. Please let us know what you were doing when this error occurred.
        We will fix it as soon as possible. Sorry for any inconvenience caused.
    </p>
</div>
</body>
</html> 

If i'm looking in Symfony logs var/log/prod.log and no error handled. No error in /var/log/php8.3-fpm.log and in nginx log, i got only this line from /var/log/nginx/access.log (nothing in /var/log/nginx/error.log) :

xx.xx.xx.xx - - [06/Mar/2024:13:49:04 +0100] "POST /v2/api_users HTTP/2.0" 500 1017 "-" "curl/7.81.0"

GET requests are good and return data. I have an other POST route who return data, so i'm suspecting error with database; but without log i can't find the real problem. I've trying this solution from official documentation and create my own ErrorProvider without effect. var_dump($data); die(); just before return in UserPasswordHasher display entity ApiUser with all properties correctly. I'm looking for advice or a solution who return error as json (or ld+json) if request has error.

0

There are 0 best solutions below