laravie/api
A Laravel package for structuring JSON APIs with a lightweight, organized approach to endpoints and responses. Laravie API helps keep API code clean and consistent inside Laravel applications, making backend services easier to build and maintain.
laravie/api ships with very little public documentation, so treat the package source as the canonical reference. The package is small and focused: it exists to remove response-envelope boilerplate from API controllers, so the fastest path is to read the source before writing code against it.
1. Verify compatibility first — and pick the right major. v5.0.0 is the release that added Laravel 9 support. It is a major version bump for a single change, which usually means the illuminate/* constraints were raised rather than widened — i.e. v5 may drop Laravel 8 and older. Check the constraint before committing:
composer require laravie/api
composer show laravie/api
^5.0.^4.0 (or verify the v5 constraint actually permits your version).2. Where to look first.
vendor/laravie/api/src/ — the actual response helper(s), trait(s), and any service provider.vendor/laravie/api/composer.json — Laravel version constraints and autoload namespace. This is the file to read first when deciding between v4 and v5.extra.laravel.providers) or must be registered manually in config/app.php.config/ file in the package — publish it if present so you can adjust envelope keys/status codes without editing vendor code.3. First use case. Pick one controller endpoint and route it through the package’s success/error helpers rather than returning raw response()->json(...). The goal is a single, predictable envelope across the API, for example:
{ "success": true, "data": { "id": 1 }, "message": null, "errors": null }
Confirm the exact method names from the source (they may be a trait method, a facade, or a global helper) before adopting them project-wide.
Standardize the envelope in one place. The highest-value pattern is to funnel every controller return through the package’s helpers so clients get a stable shape:
// Illustrative — confirm actual helper names in the package source.
return $this->respondSuccess($user); // 200 + data
return $this->respondError('Not found', 404);
return $this->respondValidation($validator->errors()); // 422
If the package exposes only low-level helpers, wrap them in a base ApiController or a RespondsWithJson trait in your own app. That way the package’s API is an implementation detail and you can swap it later.
Treat the v4 → v5 upgrade as a constraint change, not a refactor. The 5.0.0 changelog contains nothing but Laravel 9 support, so the public API you coded against on v4 is unchanged. The upgrade is: bump the constraint, run composer update laravie/api, clear caches, run your envelope tests. If you maintain a shared internal wrapper, the bump is a one-line composer.json change for every consumer of that wrapper.
Integrate with the exception handler. Rather than try/catching in every controller, render API exceptions centrally in app/Exceptions/Handler.php (or bootstrap/app.php on Laravel 9+ / 11) using the package’s error formatter. Map framework exceptions consistently:
ValidationException → 422 with errorsModelNotFoundException / NotFoundHttpException → 404AuthenticationException → 401AuthorizationException → 403This keeps “happy path” controllers focused on application logic and makes error responses uniform without per-endpoint code.
Compose with Eloquent API Resources. If you already use JsonResource, let the resource shape the data payload and let laravie/api wrap it. Avoid wrapping twice (e.g., resource already returns {data: ...} and then the helper wraps again). Decide on one convention: either the resource returns a bare payload and the helper adds the envelope, or the resource owns the envelope.
Handle pagination explicitly. Paginated responses are the most common place envelopes drift. Create a single method that takes a LengthAwarePaginator and emits data, meta (current_page, last_page, per_page, total), and links. Test it once; reuse everywhere.
Use it in feature tests. Assert against the envelope rather than raw JSON so refactors are caught:
$response->assertOk()
->assertJsonStructure(['success', 'data' => ['id', 'email'], 'message', 'errors']);
Run this same suite on both sides of the v5 bump — it’s the cheapest way to prove the Laravel 9 support release didn’t (or did) change anything for you.
Keep controllers thin. A typical day-to-day controller becomes: authorize → validate → delegate to an action/service → return a success helper. The package earns its keep by making that last step one line.
Maintenance risk is still the biggest gotcha, but it is no longer “unmaintained.” The release cadence is slow — v5.0.0 arrives roughly two years after the May 2022 release, and the only change is Laravel 9 support. That confirms the package tracks major Laravel versions eventually, but late. Pin the version in composer.json, and keep a thin internal wrapper (base controller/trait) so you are not coupled to the package across hundreds of call sites. If a future Laravel major is unsupported, you can replace the wrapper’s internals without touching controllers.
Don’t assume v5 is a superset of v4. A major bump for a framework-support change almost always means dropped constraints. Confirm from composer.json whether Laravel 8 (and PHP versions below the Laravel 9 minimum) are still allowed. Staying on v4 is a legitimate, supported choice if you are not on Laravel 9 — but record the decision somewhere, because “why are we on v4?” is a future archaeology problem.
Confirm the provider registration. Older packages often rely on manual registration. If helpers are “undefined,” check config/app.php providers and whether the package uses auto-discovery. Run php artisan config:clear after changing provider config.
Watch for double-wrapped responses. Mixing raw response()->json(), API Resources, and package helpers produces inconsistent envelopes (data.data, or success present on some endpoints and absent on others). Audit with a single test that hits several endpoints and asserts the same top-level keys.
Error helpers and HTTP status codes. A common mistake is returning an error envelope with HTTP 200. Ensure the package’s error helper actually sets the status code; if it only formats the body, set the status explicitly. Clients and monitoring depend on real status codes.
Validation error shape. Laravel’s default validation response is {message, errors}. If your envelope nests errors differently, update the exception handler once rather than overriding failedValidation in every FormRequest.
Don’t leak internals in 500s. If the package’s error helper accepts arbitrary messages, guard against passing $e->getMessage() for unexpected exceptions in production. Log the exception; return a generic message.
Config caching. If the package publishes config, remember php artisan config:cache in deployment. Stale caches are a frequent “why is the envelope different in production?” cause — and a likely one right after a version bump.
Extension points. Prefer, in order: (1) published config, (2) your own base controller/trait wrapping the helpers, (3) subclassing the package class, (4) forking. Avoid editing files in vendor/ — they disappear on composer update.
Debugging tip. When an endpoint’s response looks wrong, temporarily dd() the value before it enters the helper, then inspect the helper’s output. This isolates whether the bug is in your payload or in the envelope formatting.
How can I help you explore Laravel packages today?