Installation:
composer require asjustas/jv-rest-bundle
Add the bundle to config/bundles.php:
return [
// ...
Justas\RestBundle\JustasRestBundle::class => ['all' => true],
];
First Use Case: Create a DTO (Data Transfer Object) for request validation. Example:
// src/Dto/UserCreateDto.php
namespace App\Dto;
use Justas\RestBundle\Validator\Constraints as RestAssert;
class UserCreateDto
{
/**
* @RestAssert\NotBlank()
* @RestAssert\Length(max=255)
*/
public string $name;
/**
* @RestAssert\Email()
*/
public string $email;
}
Configure Controller:
Use the RestController trait to auto-validate and serialize requests:
// src/Controller/UserController.php
namespace App\Controller;
use App\Dto\UserCreateDto;
use Justas\RestBundle\Controller\RestController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class UserController extends RestController
{
public function create(Request $request, UserCreateDto $dto): Response
{
// $dto is automatically validated and populated
return $this->json(['success' => true]);
}
}
Routing:
# config/routes.yaml
user_create:
path: /users
controller: App\Controller\UserController::create
methods: POST
Request Validation:
@RestAssert constraints (e.g., @RestAssert\NotBlank(), @RestAssert\Length()).Response Serialization:
jms/serializer-bundle) to serialize responses.@Serializer\SerializedName or @Serializer\Type for custom serialization logic.Exception Handling:
Justas\RestBundle\Exception\RestException for custom error responses.class ValidationException extends RestException
{
public function __construct(array $errors)
{
parent::__construct('Validation failed', Response::HTTP_BAD_REQUEST, ['errors' => $errors]);
}
}
Event-Driven Extensions:
RestRequestEvent, RestResponseEvent) to modify requests/responses globally.// src/EventListener/AddTimestampListener.php
namespace App\EventListener;
use Justas\RestBundle\Event\RestRequestEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class AddTimestampListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
RestRequestEvent::class => 'onRestRequest',
];
}
public function onRestRequest(RestRequestEvent $event)
{
$event->getRequest()->query->set('timestamp', time());
}
}
Field Inclusion Rules:
@Groups annotation to control which fields are serialized.use JMS\Serializer\Annotation as Serializer;
class UserDto
{
/**
* @Serializer\Groups({"public"})
*/
public string $name;
/**
* @Serializer\Groups({"admin"})
*/
public string $email;
}
Symfony Flex Compatibility:
jms/serializer-bundle is installed and configured (run composer require jms/serializer-bundle if missing).Doctrine Annotations:
doctrine/annotations is installed and autoloaded.Custom Constraints:
Symfony\Component\Validator\Constraint and register them as services.Testing:
public function testUserCreateDtoValidation()
{
$dto = new UserCreateDto();
$dto->name = '';
$dto->email = 'invalid-email';
$validator = $this->getValidator();
$errors = $validator->validate($dto);
$this->assertCount(2, $errors);
}
Validation Errors:
errors key. Customize this behavior by overriding the RestException or creating a custom error formatter.Circular References:
User ↔ Profile). Use @Serializer\MaxDepth or @Serializer\ExclusionPolicy to handle this.Annotation Parsing:
autoload-dev.php or composer.json for annotation loading.Event Dispatcher Order:
RestRequestEvent are dispatched early in the request lifecycle. Be mindful of dependencies (e.g., services not yet initialized).Symfony Version Mismatches:
composer.json constraints align with the bundle’s requirements to avoid autowiring issues.Enable Debug Mode:
Log Validation Errors:
use Justas\RestBundle\Event\RestExceptionEvent;
use Psr\Log\LoggerInterface;
class ValidationErrorLogger implements EventSubscriberInterface
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public static function getSubscribedEvents()
{
return [
RestExceptionEvent::class => 'onRestException',
];
}
public function onRestException(RestExceptionEvent $event)
{
$this->logger->error('Validation Error', ['errors' => $event->getException()->getErrors()]);
}
}
Check Event Subscribers:
debug:event-dispatcher to list all subscribed events and their order:
php bin/console debug:event-dispatcher
Serializer Configuration:
$serializer = $this->container->get('jms_serializer');
dump($serializer->getConfiguration());
Custom Validation Constraints:
Symfony\Component\Validator\Constraint and ConstraintValidator. Register them as services:
# config/services.yaml
App\Validator\Constraints\CustomConstraintValidator:
tags: { name: validator.constraint_validator }
Dynamic DTOs:
Justas\RestBundle\Validator\DynamicDtoValidator to validate dynamic data (e.g., from nested JSON payloads).Response Transformers:
Justas\RestBundle\Serializer\ResponseTransformer to modify serialized responses globally.Security Integration:
use Justas\RestBundle\Validator\Constraints as RestAssert;
use Symfony\Component\Security\Core\AuthenticationTokenStorageInterface;
class AdminUserDto
{
/**
* @RestAssert\Role("ROLE_ADMIN")
*/
public function isAdmin(AuthenticationTokenStorageInterface $storage)
{
return $storage->getToken()->getUser()->hasRole('ROLE_ADMIN');
}
}
How can I help you explore Laravel packages today?