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

Cqrs Http Laravel Package

lmc/cqrs-http

HTTP layer for CQRS in Laravel, bridging HTTP requests with commands and queries. Route endpoints to handlers with clean request mapping, validation, and response handling for maintainable, testable applications.

View on GitHub
Deep Wiki
Context7

Getting Started

lmc/cqrs-http is a thin companion to lmc/cqrs that puts an HTTP face on the query/command buses: it ships base classes for turning an incoming HTTP request into a Query or Command, dispatching it, and turning the result (or exception) back into a response. It is essentially a reference implementation extracted from LMC's own stack, so treat it as source-of-truth code rather than a documented framework.

Minimal steps:

  1. composer require lmc/cqrs lmc/cqrs-http — the HTTP package depends on the core CQRS package; the core package's README is the real manual.
  2. Check your PHP version first. 3.0.0 (the current and only recent tag, 2022-04-27) requires PHP 8.1+. On PHP 8.0 or older you cannot install it at all; there is no maintained branch that supports older runtimes.
  3. Read the package source before writing any code: vendor/lmc/cqrs-http/src/ for the base controller/dispatcher and any HttpQuery/HttpCommand interfaces, and tests/ for the only executable documentation that exists. There is no published docs site, 1 star, and 0 dependents, so assumptions from other CQRS libraries will mislead you.
  4. Check composer.json (require, php, symfony/* constraints) — 3.0.0 is a major with BC breaks in method signatures (see below), so any example you find online that predates it will not match the code you have installed.
  5. First use case: a single read endpoint. Create a concrete Query (immutable DTO), a handler, register it on the query bus, then subclass whatever AbstractController/dispatcher the package exposes to map GET /orders/{id} into that query. Get this working end-to-end (request → bus → handler → JSON) before adding commands.
  6. Second use case: one POST command with a request-to-command mapper, a handler, and a return of 201/202. This exercises the request-body binding and exception-to-status path, which is where most of the package's opinionation lives.

Do not try to wire a full CRUD API on day one. The value here is the convention layer, and you want to see exactly what the convention is (naming, routing, serialization) from the tests before you build around it.

Implementation Patterns

Controller-per-operation. The natural fit is one small controller (or invokable action) per query/command, each doing: deserialize request → build message → $bus->dispatch($message) → serialize result. Keep controllers free of domain logic; they should be ~5–15 lines. If you find yourself writing conditionals in a controller, the branch belongs in a handler.

Separate read and write paths explicitly. Route GET → query bus, everything mutating (POST/PUT/PATCH/DELETE) → command bus. Don't let a controller pick the bus based on the payload — that's how you end up with a "command" that returns a full read model and defeats the CQRS separation the package is designed around.

DTO binding from the request. Map route params, query string, and JSON body into the message constructor, ideally via a named constructor (fromRequest() on your message or a dedicated factory). Keeping this mapping in one place per message means the bus never sees a raw Request, which is what makes handlers testable without HTTP.

Middleware is where cross-cutting behavior goes. The core lmc/cqrs bus supports middleware; use it for authorization, logging (message class + correlation id), transaction wrapping on commands, and translating domain exceptions into HTTP-friendly ones. Do not put auth checks in controllers — middleware on the command bus gives you a single choke point and covers any other entrypoint (CLI, queue) you add later.

Exception → status code mapping. Decide one mapping and centralize it: validation/422, not-found/404, forbidden/403, conflict/409, everything else/500 with a generic body. If the package provides a base handler for this, use it; otherwise write a single kernel-level listener rather than try/catch in every action.

Serialize at the edge. Handlers return domain objects or read models; the controller layer (or a serializer middleware) turns that into a response. This lets the same handler back an HTTP endpoint and, later, a console command or message consumer.

Framework integration. In a Symfony app, register the buses and any HTTP dispatcher as services and tag your handlers; in a plain PSR-7 setup, wrap it in a single front controller. The package's tests are the fastest way to see which PSR-7 / symfony/http-foundation primitives it actually assumes.

Override deliberately, matching 3.x signatures. Because 3.0.0 changed method signatures, any subclass of the package's base controller/dispatcher/mapper must copy the signature from the installed 3.x source, not from a snippet. Prefer composition (wrap the base class behind your own HttpCommandBus/HttpQueryBus facade) so future signature churn stops at one file.

PHP 8.1 idioms are baked in. Expect typed properties, promoted constructor params, and possibly readonly/enums in the message and handler plumbing. Match that style in your own messages — it keeps DTO binding and serialization symmetrical and makes the 3.x source read like your code.

Version pinning. Because the package is dormant, pin it ("lmc/cqrs-http": "^3.0" or an exact 3.0.0, or a commit hash) and record the constraint alongside the lmc/cqrs version — the two move together and an unpinned upgrade of one will silently break the other. Also pin the PHP floor in composer.json ("php": "^8.1") so CI fails loudly rather than resolving an older tag.

Gotchas and Tips

  • It is effectively unmaintained. Only release of note is 3.0.0 from 2022, 1 star, no dependents, no docs. Budget for reading source and possibly forking. If the package doesn't install against your PHP/Symfony version, vendor the few classes you need rather than fighting composer constraints.
  • 3.0.0 is a real BC break, not a documentation refresh. "Change method signatures" means subclass overrides written against 2.x will fatal-error (Declaration of ... must be compatible with ...). If you inherit from or implement anything in src/, audit each override against the installed source before assuming the upgrade is clean. If you can't, stay on 2.x and pin it.
  • PHP 8.1 is a hard floor. No 8.0 support, and nothing suggests a backport is coming. On older runtimes, the decision is "upgrade PHP" or "don't use this package."
  • The core package is the real dependency. Most "how do I…" questions are answered by lmc/cqrs (bus registration, middleware, annotations), not by this repo. Start troubleshooting there.
  • No community answers. Stack Overflow and issue threads will be empty, and search results skew to 2.x-era code that no longer matches. Reproduce behavior from tests/ rather than searching; if a test doesn't cover your case, write one before changing anything.
  • Watch the request/message boundary. The most common bug with packages like this is leaking the HTTP Request into a handler, which makes the handler untestable and couples it to the transport. If the bundled mapper does this, wrap it.
  • Don't expose the bus to arbitrary input. If the design lets a request name its own message/handler class, add an allowlist of dispatchable messages. A generic POST /dispatch endpoint is a remote-code-invocation surface the moment a class name is attacker-controlled.
  • Middleware ordering matters. Auth before validation, transaction before handler, logging outermost so it captures failures. Document the order in one place; reordering is the usual cause of "the transaction didn't roll back" and "we logged the request but not the error."
  • Debugging dispatch failures. Log the resolved message class and handler class at debug level. Most "nothing happens" issues are a handler that was never tagged/registered, not a bus failure — the bus can't tell you it found zero handlers unless you configure it to throw.
  • Watch for stale Symfony contracts. 2022-era code may reference deprecated symfony/http-foundation or http-kernel APIs (e.g. older getContent()/attribute handling). Check deprecation output on boot; small shims are usually cheaper than a fork. Note the 3.0.0 notes say nothing about Symfony version support, so verify it on the Symfony you actually run.
  • Extension points to prefer: custom bus middleware, a custom message factory / argument resolver, and a response serializer. All three let you adapt the package without editing vendor code, which matters given the low release cadence — and they insulate you from the next signature change.
  • Opportunity note: the low adoption means any internal wrapper you build (a small HttpCommandBus facade, exception mapper, and test helper) is worth committing to your own repo — it will outlive this dependency and makes the eventual swap to a maintained CQRS HTTP layer a one-file change.
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.
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
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle