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.
Architecture fit. The package is a thin adapter that lets API Platform resources be modeled as Commands and Queries dispatched onto a Symfony Messenger bus. Architecturally this is the CQRS-lite pattern: the HTTP layer becomes a transport that turns requests into messages, and handlers do the work. It fits cleanly only if three preconditions hold: the application is on Symfony, it already uses API Platform for the HTTP/API surface, and it already uses Symfony Messenger for command/query handling (sync or async). If any of those is missing, the package adds a dependency without removing work. For teams standardizing on the Symfony stack, this is a natural, low-friction pattern that maps well to event-driven or async backends.
Integration feasibility. Integration is conceptually simple: annotate/attribute message classes as API Platform operations, configure the messenger buses, and handlers receive the messages. There is no heavy runtime, no separate service, no data model of its own. The real effort is not installing the package but reshaping existing endpoints and handlers into the command/query model, which is a design change more than a technical one. Feasibility is high for greenfield; medium for brownfield services with established controller logic.
Technical risk. The dominant risk is maturity and longevity, not technical difficulty. With 31 stars and a single-maintainer profile (Samuel Roze is a credible Symfony contributor), the package is effectively a piece of glue you may need to own. Specific risks to verify: API Platform 3.x compatibility (API Platform v3 was a substantial rework of metadata and resource configuration), Symfony LTS alignment, PHP version floor, whether the package is actively released or effectively archived, and test coverage of the HTTP-to-bus path including validation and error responses. Because the abstraction is thin, the “fork and own” fallback is realistic and cheap, which materially reduces the risk. Secondary risk: leaking bus semantics (async vs sync) into the API contract, since a dispatched command that queues rather than executes returns a different response shape than the client may expect.
Key questions.
Stack fit. Best fit is a Symfony application already running API Platform and Symfony Messenger, ideally with an established handler/handler-locator convention. It is a poor fit for non-Symfony stacks, for services that expose only a handful of trivial endpoints, or for teams not already comfortable with message buses. It is a strong fit for teams that want uniform request handling, validation, and async offloading across many endpoints without hand-writing controllers.
Migration path. Adopt incrementally rather than as a rewrite. Pick one bounded context or non-critical resource family, model its reads and writes as queries and commands, and route them through the package while other endpoints remain controller-based. Both styles can coexist in one application, so the migration is per-resource, reversible, and can be paused. Keep the HTTP contract stable (same paths, payloads, status codes) so clients are insulated from the internal refactor.
Compatibility. Confirm three version axes before committing: Symfony (and its LTS window), API Platform (v2 vs v3 is a real fork in behavior), and PHP. Also confirm the Messenger transport assumptions — sync in-process handling is the safe default; async transports (AMQP, Redis, Doctrine) widen the failure surface and change the API's response semantics. Pin versions and treat upgrades of API Platform as a breaking-change event for this package.
Sequencing. (1) Spike on a throwaway branch: one command and one query end-to-end, including validation, auth, and error responses. (2) Decide sync vs async per operation and document the response contract for each. (3) Establish handler conventions and a shared base for validation/authorization. (4) Migrate a low-risk resource family to production. (5) Only then expand, and only if the spike showed clean behavior. Budget an explicit decision point: adopt, vendor, or fork.
Maintenance. Ongoing maintenance is low in code volume but non-zero in attention: the package is small enough to read in an afternoon and, if abandoned, small enough to vendor into the repository. The real maintenance load is the surrounding conventions — bus configuration, handler registration, and keeping API Platform metadata in sync with message classes. Treat ownership explicitly: name a maintainer and add the package to the dependency-review checklist.
Support. Community support is thin (low star count, single maintainer). Assume self-support: internal documentation, a pinned version, and a named fallback owner. Do not place this on a critical path without a fork contingency.
Scaling. The package itself does not constrain scale; the bus does. Synchronous dispatch scales with the web tier. Asynchronous dispatch scales with worker capacity, at the cost of eventual consistency and a new class of client-facing semantics (accepted vs completed, polling or callbacks). Plan worker autoscaling, queue depth monitoring, and dead-letter handling as part of the design, not as an afterthought.
Failure modes. Watch for: bus misconfiguration producing silent no-ops (a dispatched message with no handler), validation happening in the wrong layer, authorization bypassed because the check lived in a controller that no longer exists, async failures invisible to the API consumer, serialization drift between HTTP payloads and message objects, and API Platform upgrades breaking metadata discovery. Each of these is preventable with integration tests that exercise the full HTTP-to-handler path.
Ramp-up. Modest for teams already fluent in Symfony and Messenger; steep for teams new to CQRS-style separation, because the pattern — not the package — is the learning curve. Expect a short onboarding for the wiring and a longer one for the discipline of keeping commands/queries and handlers cleanly separated. Provide a reference implementation (one command, one query, one async operation) and a short internal guide; that shortens ramp-up more than any documentation the package ships.
How can I help you explore Laravel packages today?