Installation:
composer require 4xxi/rest-request-errors
Ensure your project uses Symfony Forms or has a mechanism to handle validation errors.
Basic Setup:
Add the configuration to config/packages/rest_request_error.yaml:
rest_request_error:
use_exception_listener: true
First Use Case:
Throw FormInvalidRequestException when a Symfony form fails validation:
use Fourxxi\RestRequestError\Exception\FormInvalidRequestException;
if (!$form->isValid()) {
throw new FormInvalidRequestException($form);
}
This will automatically serialize form errors into a structured JSON response.
Form Validation Errors:
Use FormInvalidRequestException for Symfony forms to serialize nested field errors:
// Controller
public function submit(FormInterface $form, Request $request) {
$form->submit($request->request->all());
if (!$form->isValid()) {
throw new FormInvalidRequestException($form);
}
}
Custom Error Arrays:
For non-form validation errors, use ArrayInvalidRequestException:
throw new ArrayInvalidRequestException([
'email' => 'The email is invalid.',
'password' => [
'min_length' => 'Password must be at least 8 characters.',
'strength' => 'Password must include uppercase letters.'
]
]);
Exception Listener: The bundle provides an exception listener for automatic handling. Ensure it’s enabled via config:
rest_request_error:
use_exception_listener: true
Integration with API Platform/Symfony Serializer: The package integrates seamlessly with Symfony’s Serializer component. No additional setup is required if you’re already using it.
Customize Error Responses: Decorate the normalizer to modify the error payload structure:
# services.yaml
App\Serializer\CustomExceptionNormalizer:
decorates: Fourxxi\RestRequestError\Serializer\InvalidRequestExceptionNormalizer
arguments:
- '@App\Serializer\CustomExceptionNormalizer.inner'
Global Error Handling: Use the exception listener to centralize error responses across controllers:
// src/EventListener/ExceptionListener.php
use Fourxxi\RestRequestError\EventListener\InvalidRequestExceptionListener;
class CustomExceptionListener extends InvalidRequestExceptionListener {
// Override methods to customize behavior
}
Testing: Mock the exceptions in tests to verify error responses:
$this->expectException(FormInvalidRequestException::class);
$this->expectExceptionMessageJson([
'errors' => [],
'children' => [
'username' => ['errors' => ['This field is required.']]
]
]);
Archived Package: The package is archived, meaning no new updates or bug fixes will be released. Use with caution in production, especially for long-term projects.
Symfony-Specific: The package is tightly coupled to Symfony Forms and Symfony’s Serializer. It won’t work in non-Symfony Laravel projects or without Symfony’s components.
Exception Listener Dependency:
If use_exception_listener is set to true but the listener isn’t registered (e.g., missing EventListener service), errors will not be caught automatically. Verify the listener is properly loaded:
php bin/console debug:container Fourxxi\RestRequestError\EventListener\InvalidRequestExceptionListener
Nested Error Structure:
The default output includes a children array for nested fields. If your API expects a flattened structure, decorate the normalizer to transform it:
public function normalize($object, $format = null, array $context = [])
{
$normalized = $this->innerNormalizer->normalize($object, $format, $context);
return $this->flattenErrors($normalized);
}
private function flattenErrors(array $errors): array
{
$flattened = [];
foreach ($errors['children'] as $field => $child) {
$flattened[$field] = $child['errors'];
}
return ['errors' => $flattened];
}
Check Serialization: If errors aren’t appearing in the response, verify the exception is being thrown and the listener is active. Log the exception:
try {
// Risky code
} catch (FormInvalidRequestException $e) {
\Log::error('Form error:', ['exception' => $e]);
throw $e;
}
Normalizer Decoration:
If decorating the normalizer, ensure the inner service is correctly injected. Use:
arguments:
- '@.inner' # Note the dot prefix for decorated services
Configuration Overrides:
If the config file isn’t found, manually register the listener in config/services.yaml:
services:
Fourxxi\RestRequestError\EventListener\InvalidRequestExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
Custom Error Formats: Extend the normalizer to support additional error types (e.g., API-specific codes):
public function normalize($object, $format = null, array $context = [])
{
$normalized = $this->innerNormalizer->normalize($object, $format, $context);
$normalized['meta'] = ['code' => 422, 'source' => 'validation'];
return $normalized;
}
Localization: Add support for localized error messages by overriding the normalizer:
public function normalize($object, $format = null, array $context = [])
{
$normalized = $this->innerNormalizer->normalize($object, $format, $context);
$normalized['errors'] = array_map(
fn($error) => $this->translator->trans($error),
$normalized['errors']
);
return $normalized;
}
Laravel Adaptation: While not natively supported, you can adapt the package for Laravel by:
HttpFoundation components via symfony/http-foundation.public function render($request, Throwable $exception)
{
if ($exception instanceof FormInvalidRequestException) {
return response()->json(
(new InvalidRequestExceptionNormalizer())->normalize($exception),
422
);
}
return parent::render($request, $exception);
}
How can I help you explore Laravel packages today?