hardcodear / api-response-service
Servicio para formatear respuestas JSON en Laravel
Package info
github.com/hardcodear/api-response-service
pkg:composer/hardcodear/api-response-service
Requires
- php: ^8.2
- illuminate/auth: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.0|^12.0|^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-12 17:48:33 UTC
README
Paquete Laravel 12 y 13 para formatear respuestas JSON de forma estandarizada.
Este paquete proporciona una forma consistente de estructurar las respuestas JSON para APIs Laravel, siguiendo un formato uniforme para respuestas exitosas y de error.
✅ Compatibilidad
- PHP
8.2+con Laravel 12 - PHP
8.3+con Laravel 13 - Laravel
12y13
📦 Instalación
Instalar el paquete
En consola:
composer require hardcodear/api-response-service:^2.0
Laravel detectará automáticamente el ServiceProvider y registrará el alias del facade apiresponse gracias al archivo composer.json del paquete.
También podés importar el facade con su nombre completo:
use Hardcodear\ApiResponseService\Facades\ApiResponse; return ApiResponse::success('Operación realizada', ['id' => 123]);
No requiere migraciones ni cambios en la base de datos. El manejo global de excepciones es opcional y se activa por separado.
⚡ Quick Start
<?php use Illuminate\Http\Request; class UserController { public function index() { return apiresponse()->success('Listado de usuarios', [ ['id' => 1, 'name' => 'Ana'], ['id' => 2, 'name' => 'Luis'], ]); } public function store(Request $request) { $errors = []; if (! $request->input('email')) { $errors['email'][] = 'El campo email es obligatorio.'; } if ($errors !== []) { return apiresponse()->validation('Datos inválidos', $errors); } return apiresponse()->successResponse(201, 'Usuario creado', ['id' => 123]); } }
🧰 Funcionalidades disponibles
El paquete expone los siguientes métodos a través del helper apiresponse() (o facade ApiResponse):
✅ Respuestas exitosas
apiresponse()->success(?string $message = null, mixed $data = null): JsonResponse
return apiresponse()->success('Operación realizada con éxito', ['id' => 123]);
📭 Not Found (404)
apiresponse()->notFound(?string $message = null, mixed $errors = null): JsonResponse
return apiresponse()->notFound('Recurso no encontrado');
🛑 Validación fallida (422)
apiresponse()->validation(?string $message = null, mixed $errors = null): JsonResponse
return apiresponse()->validation('Datos inválidos', $validator->errors());
🔐 No autorizado (401)
apiresponse()->unauthorized(?string $message = null, mixed $errors = null): JsonResponse
return apiresponse()->unauthorized('Token inválido');
🚫 Prohibido (403)
apiresponse()->forbidden(?string $message = null, mixed $errors = null): JsonResponse
return apiresponse()->forbidden('Acceso denegado');
💥 Error del servidor (500)
apiresponse()->serverError(?string $message = null, mixed $errors = null): JsonResponse
return apiresponse()->serverError('Error inesperado');
❌ Errores personalizados
apiresponse()->error(?string $message = null, mixed $errors = null): JsonResponse
return apiresponse()->error('Error inesperado', ['detalle' => '...']);
success() siempre responde con HTTP 200 y error() con HTTP 500. Para otros códigos, usá los métodos generales:
return apiresponse()->successResponse(201, 'Creado', ['id' => 123]); return apiresponse()->errorResponse(429, 'Intentá más tarde', headers: ['Retry-After' => '60']);
🧪 Estructura del JSON resultante
Éxito
{
"status": 200,
"message": "Mensaje opcional",
"data": {
"id": 123
}
}
Error
{
"status": 500,
"message": "Mensaje de error",
"errors": [
{ "email": ["El campo email es obligatorio."] }
]
}
El campo
errorspuede ser un array plano o un array asociativo (por ejemplo, errores de validación).
Los arrays indexados se conservan sin cambios. Los arrays asociativos se envuelven como un elemento de errors, y un array vacío se mantiene como [].
Cuando
dataoerrorssonnull, esas claves se omiten automáticamente del JSON.
message siempre está presente y puede ser null. status coincide con el código HTTP real.
📌 Manejo global de excepciones (opcional)
Si querés que tu API devuelva respuestas JSON uniformes ante errores comunes como rutas no encontradas, permisos o límites de peticiones, podés usar el registrador de excepciones incluido en este paquete.
Esto te permite centralizar el manejo de errores en bootstrap/app.php, sin repetir lógica en cada controlador.
🧱 Editar bootstrap/app.php
Agregá el binding dentro del withExceptions(...) existente en bootstrap/app.php, antes de create(). Por ejemplo:
use Hardcodear\ApiResponseService\ExceptionApiRegistrar; use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { // Conservá la configuración de middleware de tu aplicación. }) ->withExceptions(function (Exceptions $exceptions): void { ExceptionApiRegistrar::bind($exceptions); })->create();
Conservá las rutas y callbacks de tu aplicación; la línea necesaria es ExceptionApiRegistrar::bind($exceptions). Si tu proyecto no tiene routes/api.php, crealo antes de añadirlo a withRouting.
⚙️ ¿Qué hace esto?
Intercepta excepciones comunes y devuelve respuestas formateadas como:
{
"status": 404,
"message": "URL no encontrada"
}
Las excepciones manejadas por defecto son:
- AccessDeniedHttpException → 403 Forbidden
- NotFoundHttpException → 404 Not Found
- TooManyRequestsHttpException → 429 Too Many Requests
- RouteNotFoundException → 401 Unauthorized
- AuthenticationException → 401 Unauthorized
- AuthorizationException → 403 Forbidden
- MethodNotAllowedHttpException → 405 Method Not Allowed
- ValidationException → 422 Unprocessable Entity
- ServiceUnavailableHttpException → 503 Service Unavailable
- HttpExceptionInterface (fallback) → respeta el status HTTP en rutas API; los mensajes 5xx se reemplazan por un mensaje seguro
Los headers Allow (405) y Retry-After (429 y 503), así como los del fallback HTTP, se conservan en la respuesta JSON.
Las rutas fuera de api_patterns y las excepciones que no figuran en esta lista siguen siendo manejadas por Laravel. Por ejemplo, una RuntimeException conserva el manejo de errores de la aplicación.
⚙️ Configuración opcional
Si querés personalizar patrones de rutas y mensajes, publicá la configuración:
php artisan vendor:publish --tag=apiresponse-config
Archivo publicado: config/apiresponse.php
api_patterns: patrones de ruta a interceptar (default:['api', 'api/*'])messages: mensajes por tipo de excepcion
🧪 Testing
Ejecutar la suite localmente:
composer install
composer test
El repositorio también ejecuta tests automáticamente en GitHub Actions para push y pull_request, validando Laravel 12 con PHP 8.2+ y Laravel 13 con PHP 8.3+ en combinaciones compatibles.
Matriz de versiones recientes:
| PHP | Laravel |
|---|---|
8.2 |
12 |
8.3 |
12 |
8.3 |
13 |
8.4 |
12 |
8.4 |
13 |
8.5 |
12 |
8.5 |
13 |
Además, se prueban las dependencias mínimas declaradas para Laravel 12/PHP 8.2 y Laravel 13/PHP 8.3.
CI también instala el archivo distribuible en aplicaciones Laravel 12 y 13 nuevas, sin las dependencias de desarrollo del paquete. Verifica autodiscovery, helper, facade y alias, publicación de configuración, config:cache y respuestas a través del kernel HTTP real. El check CI solo pasa si toda la matriz y ambas instalaciones pasan.
Las dependencias de producción recientes se revisan con composer audit. La matriz de dependencias mínimas comprueba compatibilidad; para uso en producción, mantené actualizadas las dependencias de tu aplicación.
Para contribuir, consultá CONTRIBUTING.md. El historial está en CHANGELOG.md, los reportes privados de seguridad en SECURITY.md y el proceso de releases en docs/RELEASING.md.
Migración a v2.0
AccessDeniedHttpExceptionahora responde correctamente con 403 en lugar de 401.- Las excepciones HTTP 5xx conservan su status original; su mensaje interno no se expone.
- Los headers HTTP de las excepciones se preservan.
- Un array vacío enviado como
errorspermanece como[]. - La estructura y los nombres de las claves JSON no cambian.
🧑 Autor
Ricardo Bazán
Argentina, 2026
Repositorio: https://github.com/hardcodear/api-response-service
📄 Licencia
Este paquete está licenciado bajo la MIT License.