Laravel API Response
A Composer package — `satheez/laravel-api-response` — that gives Laravel apps a single, consistent JSON response layer. One helper, twelve pre-built status methods, zero per-controller boilerplate.
Problem
Laravel projects almost always reinvent the same small abstraction: a JSON response envelope. One controller returns ['data' => $result], another returns ['success' => true, 'payload' => $result], a third throws an exception that leaks a stack trace to the client. Every team writes its own version, slightly differently, and consumers of the API end up handling N shapes for the same conceptual response.
The goal of satheez/laravel-api-response is to remove that decision from each project: pull in one Composer package, get a consistent response shape, move on.
Constraints
- Zero-config defaults —
composer require satheez/laravel-api-response, thenapi()->success($data)should just work. No mandatory configuration step. - Drop-in compatibility — must not require rewriting existing controllers. Adoption should be incremental, controller-by-controller.
- Idiomatic Laravel — feels native to anyone reading the code. Uses the helper-function pattern Laravel already leans on.
- Small surface area — a response envelope is a utility, not a framework. Keep the API tight enough to memorise.
Key decisions
- Global
api()helper instead of a base controller — controllers don’t extend a new class, don’t use a trait. They just callapi()->success(...), the same way they’d callresponse()->json(...). Composable with any existing class hierarchy. - One method per HTTP semantic — twelve named methods covering the realistic surface:
success(),created(),updated(),unauthorized(),invalidRequest(),accessDenied(),forbidden(),notFound(),validationError(),somethingWentWrong(),exception(), plus a genericerror()andsuccess()overload for custom status codes. Each method maps to its conventional HTTP code (200/201/400/401/403/404/422/500). - Consistent envelope shape — every response uses the same outer keys, regardless of which method produced it. Clients only need to learn one structure.
- Exception → response in one call —
api()->exception($e)normalises any thrown exception into the same envelope, so the global exception handler stays one line. No more leaked stack traces in production responses. - Publishable config for the rare project that needs it —
php artisan vendor:publish --tag="api-response-config"exposes the defaults for projects with non-standard API contracts. The 90% case never touches it. - Distributed via Packagist —
composer requireis the entire install step. Updates flow through normal Composer workflows. - MIT licence — adoption-friendly for both internal and external projects.
Example usage
// Success
return api()->success(User::all()->toArray());
// Created (201)
return api()->created($user->toArray());
// Not found (404)
return $user
? api()->success($user->toArray())
: api()->notFound();
// Validation (422)
return api()->validationError('Email already in use');
// Catch-all
return api()->exception($exception);
The controller no longer encodes any opinion about response shape. That decision lives in one place — the package — and is uniform across the codebase.
Outcome
satheez/laravel-api-response is published on Packagist and used as the standard API response layer across multiple eFutures projects. New services adopt it during scaffold; older services migrate controller-by-controller without breaking changes.
The maintenance benefit shows up in code review: response-shape arguments stop happening. The shape is settled.
What I’d do differently
The envelope keys are currently fixed. Projects with strict API contracts (for example, an external partner that mandates code and payload instead of success and data) cannot adopt without a fork. A future version will let the envelope keys be configured per app — keeping the zero-config default intact while making the package usable in projects with imposed response shapes. The README also still ships with skeleton-template placeholder text in the description; replacing it with a proper readme is on the same shortlist.