laravel-api-responder maintained by yousef-ahmed-abdalgawad
Laravel API Responder
A lightweight Laravel package that standardizes JSON API responses and handles HTTP exceptions automatically — so every endpoint returns a consistent, predictable structure. easy to use
Features
- ✅ Unified JSON response format across all endpoints
- ✅ Trait with helpers for every common HTTP status code
- ✅ Automatic exception handling (401, 403, 404, 405, 422, 429, 500…)
- ✅ Pagination support built-in
- ✅ Laravel auto-discovery — zero manual registration
- ✅ Supports Laravel 11, 12, and 13
Installation
composer require yousef-ahmed-abdalgawad/laravel-api-responder
The package is auto-discovered by Laravel. No need to register the service provider manually.
Usage
1. ApiResponser Trait
Use the trait in any controller to get access to all response helpers:
use YousefAhmedAbdalgawad\ApiResponder\Traits\ApiResponser;
class UserController extends Controller
{
use ApiResponser;
public function index()
{
$users = User::paginate(10);
return $this->successResponse(
$users->items(),
'Users fetched successfully',
200,
[
'total' => $users->total(),
'per_page' => $users->perPage(),
'current_page' => $users->currentPage(),
'last_page' => $users->lastPage(),
]
);
}
public function show(User $user)
{
return $this->successResponse($user, 'User found');
}
public function destroy(User $user)
{
$user->delete();
return $this->successResponseWithoutData('User deleted successfully');
}
}
2. ApiExceptionHandler
Register the package's exception handler in your bootstrap/app.php to automatically handle common HTTP exceptions with a consistent JSON format:
use YousefAhmedAbdalgawad\ApiResponder\Exceptions\ApiExceptionHandler;
->withExceptions(function (Exceptions $exceptions): void {
ApiExceptionHandler::register($exceptions);
})
That's it — all API exceptions will now return structured JSON responses automatically.
Available Trait Methods
Success Responses
| Method | Status | Description |
|---|---|---|
successResponse($data, $message, $statusCode, $pagination) |
200 |
Return data with optional pagination |
successResponseWithoutData($message, $statusCode) |
200 |
Return message only, no data |
Error Responses
| Method | Status | Description |
|---|---|---|
errorResponse($message, $statusCode, $errors) |
any | Generic error with optional errors array |
unauthorizedResponse($message) |
401 |
Authentication required |
forbiddenResponse($message) |
403 |
Access denied |
notFoundResponse($message) |
404 |
Resource not found |
methodNotAllowedResponse($message) |
405 |
HTTP method not allowed |
conflictResponse($message) |
409 |
Duplicate / conflict |
badRequestResponse($message) |
400 |
Bad request |
requestEntityTooLargeResponse($message) |
413 |
Payload too large |
unsupportedMediaTypeResponse($message) |
415 |
Wrong content type |
serverErrorResponse($message) |
500 |
Internal server error |
serviceUnavailableResponse($message) |
503 |
Service unavailable |
Automatic Exception Handling
When ApiExceptionHandler::register($exceptions) is called, the following exceptions are caught and formatted automatically for API requests (api/* or expectsJson()):
| Exception | Status | Message |
|---|---|---|
ValidationException |
422 |
First validation error message |
ThrottleRequestsException |
429 |
Too many requests + retry_after seconds |
AuthenticationException |
401 |
Unauthorized |
NotFoundHttpException |
404 |
Route not found |
MethodNotAllowedHttpException |
405 |
Method not allowed |
AccessDeniedHttpException |
403 |
This action is unauthorized |
ModelNotFoundException |
404 |
Resource not found |
QueryException |
409 / 500 |
Duplicate entry or database error |
Throwable (fallback) |
500 |
Unexpected error |
Response Format
All responses follow this consistent structure:
Success
{
"status": 200,
"success": true,
"message": "Users fetched successfully",
"data": [...],
"pagination": {
"total": 50,
"per_page": 10,
"current_page": 1,
"last_page": 5
}
}
Error
{
"status": 422,
"success": false,
"message": "The email field is required.",
"errors": {
"email": ["The email field is required."]
}
}
Rate Limited (429)
{
"status": 429,
"success": false,
"message": "Too many requests. Please slow down.",
"retry_after": 45
}
Overriding the Exception Handler
You can override any specific handler after calling register() — Laravel renders exceptions in registration order:
->withExceptions(function (Exceptions $exceptions): void {
// Register package handlers first
ApiExceptionHandler::register($exceptions);
// Then override specific ones for your app
$exceptions->render(function (QueryException $e, $request) {
// Your custom logic here
});
})
Requirements
- PHP
^8.1 - Laravel
^11 | ^12 | ^13
License
The MIT License (MIT). Please see the LICENSE file for more information.