Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Platform Messenger Laravel Package

sroze/api-platform-messenger

Integrates Symfony Messenger with API Platform so create, update, and delete operations are dispatched as messages to a bus instead of handled inline. Route resource persistence through message handlers, run writes asynchronously, and keep your API resources thin with clean, CQRS-style separation.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package alongside its two hard dependencies:

    composer require sroze/api-platform-messenger
    

    You need a working Symfony app with symfony/messenger and api-platform/core already configured (a messenger.yaml with at least one bus, and API Platform exposing resources).

  2. Look first at the package's README.md, tests/, and any example/ or docs/ folder. This is a small (31★) package, so the tests are the most reliable specification you'll find. Pay attention to how the package registers its API Platform data provider / data persister (or operation) — that's the integration point you'll be depending on.

  3. Register the bundle if the package ships one (check vendor/sroze/api-platform-messenger/src/*Bundle.php). If there's no bundle, look for a compiler pass or a service you must alias manually.

  4. Verify the wiring with:

    bin/console debug:router
    bin/console debug:messenger
    

    You should see your message classes appear as routes, and the handler should be attached to the right bus.

  5. First use case — replace a hand-written controller with a message. The canonical pattern is a CreateBook command exposed as POST /books:

    #[ApiResource(
        operations: [new Post()],
        messenger: true,   // or the package-specific attribute/annotation
    )]
    final class CreateBook
    {
        public string $title;
    }
    

    You dispatch nothing yourself — API Platform deserializes the request body into CreateBook, the package pushes it onto the bus, and your CreateBookHandler does the work. Return a DTO (or null) and the package turns it into the response.

Implementation Patterns

  • Commands for writes, Queries for reads. Keep one message class per operation. CreateBook, UpdateBook, DeleteBook as commands; GetBook, ListBooks as queries. This mirrors the CQRS split the package is designed around and keeps routing predictable.
  • One bus per concern. Wire command.bus and query.bus in messenger.yaml and let the package's attribute/annotation pick the bus. This is where the package pays off — you can enforce "queries are synchronous, commands are async" purely in config.
  • Message class is the request DTO. Use API Platform + Symfony Serializer groups on the message itself rather than a separate DTO. Add validation constraints (#[Assert\NotBlank], #[Assert\Length]) directly on the message properties — API Platform will run the validator before the bus dispatch.
  • Handler returns the response body. For queries, have the handler return a DTO or array; the package hands it back to API Platform's normalizer, so your existing serialization groups apply. Returning void/null typically becomes 204 No Content.
  • Exception → HTTP mapping via a Symfony listener. Throw a domain exception in the handler and add an ExceptionListener/kernel.exception subscriber to convert it to the right status code (404 for BookNotFound, 422 for validation, etc.). Don't try to catch exceptions inside the handler — that's not where HTTP lives.
  • Security stays where you know it. Add #[IsGranted] or an API Platform security string on the resource operation; the package doesn't replace Symfony Security. Voters keyed on the message class work well.
  • Async commands, sync queries. Put write buses on a transport (e.g. async) and read buses in-memory. A query must return synchronously or the response is empty — never route queries through an async transport.
  • Compose with API Platform features. Filters, pagination, and OpenAPI docs continue to work on the query side; the generated OpenAPI is what your frontend consumes. This is the main benefit over hand-rolled controllers: you get docs, validation, and serialization for free while keeping the CQRS shape.
  • Testing. Unit-test handlers in isolation (nothing Symfony-specific). For the HTTP edge, use Symfony's KernelBrowser against the generated routes — same as testing any API Platform resource.

Gotchas and Tips

  • Version lock is critical. This package was built for API Platform 2.x and Symfony 4/5-era Messenger. API Platform 3 rewrote the metadata/operation system (attributes replaced annotations, DataProvider/DataPersister interfaces changed signatures). Expect to either pin api-platform/core:^2.x or patch the package's integration classes. Check the composer.json constraints before you commit.
  • Confirm the attribute/annotation name. The exact attribute (or YAML/XML config) is defined in the package source, not always clearly documented in the README. Grep vendor/sroze/api-platform-messenger/src for Attribute classes and use what's actually there.
  • Async + response body = confusion. If a command bus has an async transport, the handler's return value is never serialized — the response will be empty or the message envelope. Keep async commands returning void and use 202 Accepted semantics; use sync queries for anything you want to read back.
  • Validation ordering. Validation runs on deserialization before dispatch. If you also validate inside the handler, you'll get duplicated errors. Keep assertions on the message class and out of the handler.
  • Serializer groups on both directions. Because the message is both input and (often) output, you may need separate input/output groups or a distinct response DTO returned by the handler — otherwise you leak internal fields or fail to expose computed ones.
  • Debugging failed dispatches. Use bin/console messenger:failed:show and messenger:failed:retry. In dev, enable the Messenger data collector in the profiler; it shows the exact message dispatched, the bus, and handler failures. Combine with debug:router to confirm the operation was actually registered.
  • Route collisions. Two message classes with the same resource name will fight over routes. Keep the routePrefix/operation name explicit on each message, and check debug:router after adding a new one.
  • OpenAPI generation can silently drop operations if the message class lacks proper type information (e.g. untyped constructor params). Type every property; API Platform infers request/response schemas from those types.
  • Extension points to know: the package's data persister/provider and any bus-resolving service are where you'd customize behavior (custom bus selection, envelope stamps added before dispatch). If you need middleware (logging, tenancy, tracing), add Messenger middleware — that's still the right seam, not a package-specific hook.
  • Maintenance reality check. 31 stars means sparse docs and slow fixes. Budget time to read the source, vendor-patch a fork if API Platform upgrades break it, and write your own smoke test that asserts POST /your-resource reaches the handler — that test is your early-warning system for upgrades.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment