src83 / laravel-api-response
Unified REST API Response formatter for Laravel with exception handling, localization, logging, and pagination
Requires
- php: ^8.2
- illuminate/http: ^9.0|^10.0|^11.0
- illuminate/log: ^9.0|^10.0|^11.0
- illuminate/pagination: ^9.0|^10.0|^11.0
- illuminate/support: ^9.0|^10.0|^11.0
- illuminate/validation: ^9.0|^10.0|^11.0
Requires (Dev)
- larastan/larastan: ^2.0
- laravel/pint: ^1.0
- orchestra/testbench: ^7.0|^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-07-31 22:48:47 UTC
README
LaravelApiResponse is a Laravel package for building consistent and well-structured REST API JSON responses.
Includes automatic exception handling, module-aware localization, structured logging, and pagination out of the box.
Available in other languages: RU
Table of contents
- Introduction
- Requirements
- Installation
- Quick start
- Features
- Design principles
- Documentation
- Changelog
- License
Introduction
Every Laravel API developer has hit the same wall: an exception fires, and instead of JSON your client gets a wall of HTML. laravel-api-response fixes that — and while it's at it, gives every response a consistent, predictable structure your frontend can always rely on.
Every response carries a structured message object with a machine-readable key and a human-readable gui string resolved from your translation files. Errors additionally include a sys field for internal context.
Success response example:
{
"success": true,
"http_code": 201,
"http_text": "Created",
"message": {
"key": "user.created",
"gui": "User created successfully"
},
"meta": null,
"data": {
"id": 42,
"email": "user@example.com"
}
}
Error response example (including exceptions — always JSON, never HTML):
{
"success": false,
"http_code": 422,
"http_text": "Unprocessable Content",
"message": {
"key": "user.unprocessable_content",
"gui": "Validation error",
"sys": "The email field is required"
},
"details": {
"fields": {
"email": ["The email field is required."]
}
}
}
data and details are mutually exclusive — data and meta appears in success responses, details in errors. meta is null for simple responses and carries pagination data when the response is paginated.
Requirements
| Versions | |
|---|---|
| PHP | 8.2 or higher |
| Laravel | 9, 10, or 11 |
Installation
1. Require the package:
composer require src83/laravel-api-response
2. Run the installer:
php artisan api-response:install
The installer adds some things and modifies others in your existing project. You can review these targeted changes by running git status after executing the installation command.
In particular, pay close attention to Handler.php and Authenticate.php.
This package can be installed both on a fresh Laravel application and on an existing project with substantial business logic and a customized exception handler.
Depending on the project, the installer may behave differently (adaptively):
-
In a new, clean Laravel project, these two files will be fully updated during installation. However, they still require a quick review before you accept the changes. Once the installation is complete, you can immediately proceed to the next step
Verify the installationto make sure the package was installed correctly. -
When installing the package into a more mature project,
Handler.phpandAuthenticate.phpmay not be updated immediately if the installer detects that they already contain customized logic. Such items will be marked asACTION REQUIRED. This is normal behavior. In any case, proceed to the next stepVerify the installation.
3. Verify the installation:
php artisan api-response:check
Confirms that all components have been installed correctly.
If anything shows ACTION REQUIRED, the installer detected existing custom logic in that file and did not overwrite it automatically.
In this case:
- Back up the files marked
ACTION REQUIRED; - Force-update them by running:
php artisan api-response:check --fix
- Manually resolve any conflicts between the existing and new logic in the updated files.
That's it — the package is installed and ready to use.
You can run php artisan api-response:check one more time to confirm, then get to the fun part.
Quick start
use Src83\LaravelApiResponse\Enums\MessageKeyEnum; use Src83\LaravelApiResponse\Http\Responses\ApiErrorResponse; use Src83\LaravelApiResponse\Http\Responses\ApiSuccessResponse; use Symfony\Component\HttpFoundation\Response; // List — no messageKey needed return ApiSuccessResponse::make(data: UserResource::collection($users)); // Store return ApiSuccessResponse::make( data: new UserResource($user), httpCode: Response::HTTP_CREATED, messageKey: MessageKeyEnum::CREATED, ); // Error return ApiErrorResponse::make( httpCode: Response::HTTP_NOT_FOUND, messageKey: 'user.not_found', sysMessage: $e->getMessage(), );
For a full reference — call signatures, response shapes, and pagination — see the docs/api-contract.md
Features
- Consistent JSON contract — every response, including exceptions, returns the same structure
- Exception → JSON — HTTP and domain exceptions are caught and rendered as structured errors, never as HTML
- Module-aware localization —
guimessages are resolved fromlang/{locale}/api_response.phpby module and key - Pagination — built-in
ApiPaginatorfor Eloquent paginators andArrayPaginatorfor plain arrays - Structured logging — separate channels for throwable errors, rendered errors, missing translations, and business warnings
- Middleware stack —
ForceAcceptJson,BindRequestContext(request ID),WrapApiResponse,AppendExecutionTimeMeta,ForceContentType - Execution time — optional
meta.execution_timefield for diagnosing slow endpoints - Artisan commands —
api-response:installandapi-response:check [--fix] - Built-in exceptions —
DomainLayerExceptionandItemNotFoundExceptionready to throw from your domain layer - Request macros —
$request->isApi()and$request->apiModule()available out of the box - Standard action vocabulary —
MessageKeyEnumcovers all common CRUD and status keys
Design principles
- Controllers don't build messages — they pass a
messageKey, the package resolves the translation messageKeycan be aMessageKeyEnumvalue, a plain string, or a compoundmodule.key- The module is derived automatically from the route prefix — no manual configuration needed per endpoint
- All exceptions speak the same JSON — no special cases, no HTML leaking through
Documentation
The essentials are covered in this README. Full documentation is in progress — for details, browse the inline code comments or open an issue.
- Installation → docs/installation.md
- API reference (contract + usage examples) → docs/api-contract.md
- Configuration reference → docs/configuration.md
- Localization → docs/localization.md
- Logging → docs/logging.md
- Exception handling → docs/exceptions.md
License
- Written and copyrighted © 2026 by Roman Staroseltsev
- Open-source software licensed under the MIT license
- Author: LinkedIn