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

Data Response Laravel Package

yiisoft/data-response

yiisoft/data-response provides a PSR-7 response wrapper for returning structured data from your application. It supports multiple output formats, content negotiation, and streaming, making it easy to send JSON, XML, HTML, or raw data consistently.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require yiisoft/data-response:^2.2 — PHP 8.1+, PSR-7/PSR-17/PSR-15 based, framework-agnostic. A Laravel developer can use it standalone (or behind a PSR-15 bridge), but do not expect service providers or facades.

  1. Skim src/Factory/ first. That is the new public entry point: DataResponseFactoryInterface with DataResponseFactory, FormattedResponseFactory, HtmlResponseFactory, JsonResponseFactory, PlainTextResponseFactory, XmlResponseFactory.
  2. Then src/Formatter/ (FormatterInterface → HtmlFormatter, JsonFormatter, PlainTextFormatter, XmlFormatter).
  3. Then src/Middleware/ (DataResponseMiddleware plus the per-format variants and ContentNegotiatorDataResponseMiddleware).

First use case — return JSON from an action without hand-rolling Response objects:

final class UserController
{
    public function __construct(private JsonResponseFactory $factory) {}

    public function show(int $id): DataResponseInterface
    {
        return $this->factory->createResponse(['id' => $id, 'name' => 'Ada']);
    }
}

Then register the middleware once (Yii3: config/web/params.php / middleware stack; Laravel: a thin middleware that runs the PSR-15 middleware and converts the resulting PSR-7 response back). For negotiation-style APIs, prefer ContentNegotiatorResponseFactory + ContentNegotiatorDataResponseMiddleware over per-action factories.

Implementation Patterns

Inject a specific factory, not the container. JsonResponseFactory / HtmlResponseFactory in the constructor makes the contract obvious and keeps tests trivial (new JsonResponseFactory(new JsonFormatter(...))).

Wire DataResponseMiddleware once in the stack. It is the single place that turns DataResponseInterface into a real ResponseInterface. Per-format middlewares (JsonDataResponseMiddleware, etc.) are for handlers that return the bare DataResponseInterface and should always be serialized the same way — handy for webhook/health endpoints.

Negotiated APIs. ContentNegotiatorDataResponseMiddleware reads Accept and delegates to the factory that can satisfy it. Keep a default format explicitly configured so Accept: */* and missing headers are deterministic; add a 406 path for unsupported types rather than silently falling back.

Custom formats. Implement FormatterInterface (one method returning a formatted DataResponseInterface) and plug it into FormattedResponseFactory. This is the extension point for CSV, Problem+JSON (application/problem+json), or your house error envelope. Register the media type in the negotiator so it participates in Accept matching.

Large or streamed payloads. DataStream lets you hand over a callable that produces the body lazily — use it for exports and paginated dumps so you are not building multi-megabyte arrays in memory. Compose it inside the factory call and set Content-Disposition on the response afterwards.

Laravel glue. Because the package speaks PSR-7, treat it as the "response construction" layer only: a small middleware converts DataResponseInterface → PSR-7 → Symfony\Component\HttpFoundation\Response (or response()->stream() for DataStream), and you keep Laravel's routing, validation, and auth untouched. Do not attempt to replace Illuminate\Http\Response wholesale.

Testing. Assert on the DataResponseInterface (data, headers, status) in unit tests, and on the converted PSR-7 response in integration tests. The middleware is the only thing that needs a real request.

Gotchas and Tips

Two namespaces, identical short names. 2.2.0 deprecates the root-namespace classes (DataResponse, DataResponseFactory, DataResponseFactoryInterface, DataResponseFormatterInterface, HtmlDataResponseFormatter, ContentNegotiator, FormatDataResponse* middlewares) and adds replacements in Factory\, Formatter\, and Middleware\. IDE auto-import will happily pull the deprecated one — alias imports explicitly and grep for ResponseContentTrait / FormatDataResponse in your codebase.

The renames are not 1:1 by name. FormatDataResponse → DataResponseMiddleware; FormatDataResponseAsJson → JsonDataResponseMiddleware; JsonDataResponseFormatter → JsonFormatter. Read the deprecation list once and do the migration in a single pass; the old classes still work in 2.2 but will disappear in 3.0.

Middleware ordering matters. It must run after whatever decides the response (controller/action handler) and before the emitter. If a later middleware returns a plain PSR-7 response, the data-response middleware never sees it — silent pass-through, no error.

It only handles DataResponseInterface. Returning an array, a string, or Illuminate\Http\JsonResponse from a handler bypasses formatting entirely. That is by design, but it makes "why is my JSON not formatted?" the most common debugging session.

Header precedence. Formatters set Content-Type; your controller-set headers may be overwritten or may win depending on ordering. Set Content-Type via the formatter, not manually, and assert it in a test — the failure mode is a text/html body served as application/json.

DataStream is lazy, sometimes single-use. Don't read it twice (logging middleware that calls __toString(), then the emitter, will consume or rewind it depending on the callable). Buffer deliberately if you need to log bodies, and don't assume a Content-Length — chunk or compute it yourself.

XmlFormatter needs ext-dom/SimpleXML. Verify the extension is present in the runtime image; also check how it renders empty arrays, attributes, and numeric-indexed lists — the output shape is opinionated and often not what an XML client expects.

Negotiation quirks. Accept parsing is q-value aware; wildcard subtypes and vendor types (application/vnd.api+json) need to be registered. Set an explicit default format and decide explicitly between 406 and fallback — the default behaviour surprises people either way.

Composer housekeeping. 2.2.0 strips non-runtime files from the archive (Enh #108), and use statements are now explicit (Enh #106). Nothing to do at runtime, but stop referencing anything under a package's tests/ or docs/ path from your own tooling — it was never supported and is gone.

Debugging shortcut. When a response looks wrong, dump the DataResponseInterface before the middleware (data + status + headers) and the PSR-7 ResponseInterface after. Almost every bug is in one of those two, not in both.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource