← All projects

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.

Role
Author & Maintainer
Period
Open source
Team
Independent build
Stack
PHP · Laravel · Composer · Packagist

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 defaultscomposer require satheez/laravel-api-response, then api()->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 call api()->success(...), the same way they’d call response()->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 generic error() and success() 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 callapi()->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 itphp 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 Packagistcomposer require is 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.