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 Api Response Helpers Laravel Package

f9webltd/laravel-api-response-helpers

Laravel API Response Helpers provides a simple trait for consistent JSON API responses in Laravel apps. Easily return success, error, not found, validation, and other common responses with standardized structures and HTTP status codes.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install: composer require f9webltd/laravel-api-response-helpers. There is nothing to publish, no config file, no facade, and no service provider setup — the entire package surface is a single trait (F9Web\ApiResponseHelpers).
  2. Check your constraints first. v4.x requires PHP ^8.2 and Laravel ^12/^13. On Laravel 11 pin ^3.1; on Laravel 8–10 pin ^2.1.1. This is the one decision that bites people during rollout, so confirm composer why-not before writing any code.
  3. Import the trait in a base API controller rather than in every controller — the README's OrdersController example works, but a shared App\Http\Controllers\ApiController is the pattern that actually pays off:
abstract class ApiController extends Controller
{
    use ApiResponseHelpers;

    public function __construct()
    {
        $this->setDefaultSuccessResponse([]);
    }
}
  1. First use case: find the inconsistencies the package was built to kill — response()->json(['error' => $e], 400), response()->json(['message' => ...], 400), response()->json([$e], 400) — and replace each with $this->respondError('...'). Start with one controller, migrate the rest as you touch them.
  2. Where to look first: src/ApiResponseHelpers.php. It's roughly a dozen short methods; reading it once tells you the exact JSON shape and status code of every helper, which is faster than scanning the README table.

Implementation Patterns

Map HTTP intent to method names, not to status codes. The value of the package is that a reviewer reads respondConflict() instead of decoding 409:

public function store(StoreOrderRequest $request): JsonResponse
{
    $order = Order::create($request->validated());

    return $this->respondCreated(OrderResource::make($order));
}

public function destroy(Order $order): JsonResponse
{
    $order->delete();

    return $this->respondNoContent();
}

Queue-backed endpoints: respondAccepted() for 202, respondTooManyRequests() for throttle ceilings, respondConflict() for optimistic-locking or duplicate-resource collisions.

Pass rich objects, not arrays. The helpers accept array|Arrayable|JsonSerializable|null, so Eloquent collections, Collection, and JsonResource all work directly:

return $this->respondWithSuccess(Invoice::pending()->get());
return $this->respondCreated(PostResource::make($post));

The package is explicitly designed to sit alongside Laravel API Resources, not replace them — keep the transformation in the Resource and let the helper own the envelope and status code.

Two ways to set the success envelope, pick one per app:

// Fluent, per-call — good for one-off endpoints
return $this->setDefaultSuccessResponse([])->respondWithSuccess($users);

// Constructor, per-controller — good for a global convention
public function __construct() { $this->setDefaultSuccessResponse([]); }

Use [] when your front end wants a bare payload ([...users]) instead of ['success' => true, ...]. This is the single knob your API contract hinges on, so set it in the base controller and document it.

Keep validation and 500s in the exception handler. These helpers cover the happy path and hand-rolled error responses; they do not intercept ValidationException (422) or unhandled exceptions. Leave bootstrap/app.php / Handler as the source of truth for those so you don't end up with two error shapes.

Testing is unchanged. Every helper returns Illuminate\Http\JsonResponse, so assertStatus, assertJson, and assertJsonStructure work exactly as before:

$response->assertStatus(201)->assertJsonStructure(['data' => ['id', 'total']]);

Gotchas and Tips

  • respondNoContent() changed in 4.0.0. It now takes zero arguments and returns an empty body per RFC 9110. If you're upgrading from 3.x, grep -rn "respondNoContent(" for any caller passing data — those arguments are now ignored (and were @deprecated since 3.1.0 as a pre-warning).
  • The $key parameter is new in 4.0.0. All error helpers accept ?string $key = 'error' as the last argument. If your front end parses message rather than error, pass key: 'message' explicitly or you'll silently change your error contract on upgrade.
  • No automatic data wrapper. respondWithSuccess($users) puts the users at the top level of the JSON body. Clients expecting { "data": [...] } will break. Either use setDefaultSuccessResponse() carefully, or wrap in an API Resource that produces the data key itself.
  • null and [] are not interchangeable. respondWithSuccess() with no argument returns ['success' => true]; respondWithSuccess([]) returns an empty object/array (and interacts with setDefaultSuccessResponse). Release 1.5.0 specifically fixed null/empty handling — be deliberate about which you pass.
  • respondFailedValidation does not exist in current versions. It appeared in v1.0.4 and is absent from the v4 method list. Don't reach for it from old blog posts; use Laravel's built-in 422 handling.
  • Trait state is per-instance. setDefaultSuccessResponse() writes a property on the controller object. It is not a global singleton — a controller that doesn't call it (or inherit from your base) keeps the ['success' => true] default.
  • No extension points, and that's fine. There's no config, no macro support, no binding. If you need extra shapes, add thin methods on your base controller that delegate to the trait (respondDeleted() → respondNoContent()); the trait is small and stable enough that wrapping is cheaper than forking.
  • Laravel 11 is a dead end on 4.x. Pin ^3.1 if you're not ready to upgrade the framework, and plan the jump — 4.0.0 is where the $key and respondNoContent changes land, so both hit at once.
  • Debugging: $this->respondError() returns a JsonResponse; inspect it with ->getStatusCode() and ->getContent() in tinker, or dd() it in a route closure. When a response "looks wrong," check whether the base controller's constructor ran — an action that overrides __construct() without calling parent::__construct() loses your default envelope.
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.
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
adachsoft/changelog-linter