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

Laravel Json Response Laravel Package

andrey-helldar/laravel-json-response

A Laravel package for building consistent JSON API responses with a fluent helper, standard success and error payloads, HTTP status codes, headers, and resource support, simplifying controller output and keeping API responses uniform.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm the surface area first.

composer require andrey-helldar/laravel-json-response
php artisan about          # sanity-check the framework version resolved

The package is a conventional Composer library with Laravel auto-discovery, so there is no service-provider registration step. Before writing any code, spend ten minutes in vendor/andrey-helldar/laravel-json-response/:

  1. src/ — the package is deliberately small. The whole feature surface is one or two classes plus a facade/trait. Read them end to end; that is the real documentation.
  2. composer.json — confirm the illuminate/* constraint and the minimum PHP version. 3.2.0 is the release that adds Laravel 13 support, so pin ^3.2 if you're on 13 and don't expect earlier 3.x to work there.
  3. config/ — if a config file ships, publish it and read the keys before you rely on defaults. If nothing ships, there's nothing to publish; don't hunt for a provider that isn't there.

The repository is archived. Treat the source in vendor/ as the authoritative spec, not the README, and expect no upstream fixes. That doesn't disqualify it — the scope is small enough to fork — but it changes how you consume it (see Gotchas).

First use case: make one endpoint consistent, then copy it.

Pick a single controller method that currently returns response()->json([...]) by hand. Replace it with the package helper, confirm the payload shape and status code in the browser or via php artisan route:list + curl, then standardise the rest of the controller around that shape. Don't refactor the whole API in one pass — the value here is a convention, and the convention is easier to agree on when you can see one endpoint rendered.

// before
return response()->json(['data' => $user, 'message' => 'OK'], 200);

// after (illustrative — verify exact helper names in src/)
return json_response()->success($user);

Implementation Patterns

1. Wrap the package in one internal class

Given the archived status, do not let the package's helper names leak into every controller. Create App\Support\ApiResponse with ok(), created(), noContent(), fail(), notFound(), validationFailed() methods that internally call the package. You get:

  • one place to change the envelope shape,
  • one place to swap the package out if you ever need to,
  • a grep-able symbol (ApiResponse::) instead of a global helper.

This is cheap insurance and takes fifteen minutes.

2. Fix the envelope once, in a base controller

abstract class ApiController extends Controller
{
    protected function ok(mixed $data = null, string $message = 'OK'): JsonResponse
    {
        return ApiResponse::ok($data, $message);
    }

    protected function created(mixed $data): JsonResponse
    {
        return ApiResponse::created($data);
    }
}

Every API controller extends it. New endpoints inherit the shape for free; a reviewer can spot an inconsistent response by the absence of the base class.

3. Push status codes into the helper, never into the call site

The failure mode with hand-rolled JSON is response()->json($data, 200) on an error path. Give the wrapper named methods per status (notFound(), forbidden(), unprocessable()) so the status is chosen by the method name, not by a magic number a developer has to remember.

return $this->notFound('User not found');
// not: response()->json(['error' => '...'], 404)

4. Let the exception handler own errors

The highest-leverage integration is bootstrap/app.php (Laravel 11+) / App\Exceptions\Handler. Register renderable callbacks for ValidationException, AuthenticationException, ModelNotFoundException, and AuthorizationException that return your envelope via the wrapper. Now framework-thrown errors and your controllers produce the same JSON — which is exactly the promise the package makes, and the thing hand-rolled responses always get wrong.

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(fn (ValidationException $e) => ApiResponse::validationFailed($e->errors()));
})

5. Wrap API Resources before passing them in

return $this->ok(UserResource::collection($users));

Do not pass a paginator and a data key — you'll get {"data": {"data": [...]}}. If the package doesn't handle paginators, call ->toArray() on the resource or use ->response()->getData(true) and pass that through once, deliberately, in the wrapper.

6. Test the contract, not the package

Write one test that asserts the envelope shape, then reference it from everywhere:

$response->assertOk()->assertJsonStructure(['data', 'meta', 'message']);
$response->assertJsonPath('data.id', $user->id);
$response->assertStatus(422)->assertJsonStructure(['errors' => ['email']]);

Use $this->getJson() / $this->postJson() so Laravel sends Accept: application/json — otherwise validation failures return a redirect and your assertion misfires in a way that looks like a package bug.

7. Standardise the meta block early

If you're going to carry request_id, pagination counts, or API version, decide it now and put it in the wrapper. Retrofitting a meta key across forty endpoints later is the expensive version of this decision.


Gotchas and Tips

The repository is archived — pin it and own the fork path. Use an exact or tightly-bounded constraint ("^3.2" is fine; "*" is not). Because it's MIT and a handful of files, a fork is a realistic escalation path at the next Laravel major. That's an argument for the internal-wrapper pattern above, not an argument against the package.

Version 3.2.0 is a compatibility release, not a feature release. If you're staying on Laravel 12, upgrading from 3.1 is inert — absorb it at your next routine dependency refresh. If you're going to Laravel 13, 3.2.0 is the floor. Check the resolved composer.lock diff; the realistic failure is a resolver conflict, not a runtime break.

Empty collections serialise as [], not {}. ['data' => []] becomes {"data":[]}. If your clients switch on the type of data, cast empty arrays to (object) [] or use JSON_FORCE_OBJECT selectively. This bites everyone once.

204 No Content must not carry a body. If the helper always emits a payload, don't use it for DELETE. Return response()->noContent() directly, and note in the base controller that it's the one intentional exception.

Don't mix the helper and response()->json() in the same controller. Pick one. Half-migrated controllers are where inconsistent payloads come from, and reviewers stop noticing after the third file.

Check for double-wrapping after adding API Resources. The most common post-adoption bug is {"data":{"data":...}} — the resource adds its own data key and the helper adds another. Assert the top-level keys in a test; it takes one line and catches it immediately.

Debug by inspecting the response object, not by dd() in the controller. $response->getData(true) gives you the array, $response->getStatusCode() the code, $response->headers->get('Content-Type') confirms JSON. In feature tests, $response->dump() is faster than re-reading the wrapper.

Prefer constructor injection of the response class over a global helper in services. Global helpers are convenient in controllers but awkward to fake in unit tests. If the package exposes both a facade/helper and an injectable class, inject it in anything that isn't a controller.

Extension points are limited by design. If a macro or config key exists, use it; otherwise extend your own ApiResponse wrapper rather than subclassing the vendor class. Never edit vendor/ — with an archived upstream, a lost composer install is unrecoverable.

Confirm the method names before you copy any snippet. The package is small and its README may lag the code. Ten minutes in src/ prevents a morning of chasing helper names that don't exist.

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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator