m-hidayatullahh/laravel-api-kit

Standardized API response envelope and global exception handling for Laravel 10 & 11.

Maintainers

Package info

github.com/m-hidayatullahh/laravel-api-kit

pkg:composer/m-hidayatullahh/laravel-api-kit

Transparency log

Statistics

Installs: 11

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-03 08:38 UTC

This package is auto-updated.

Last update: 2026-07-03 08:52:04 UTC


README

Standardized API response envelope + global exception handling for Laravel 10 & 11, PHP 8.1+.

One install gives every backend project the same success/error/validation/pagination shape, so the frontend writes one set of handlers instead of many.

Install

Private repo via composer.json:

{
  "repositories": [
    { "type": "vcs", "url": "git@github.com:company/laravel-api-kit.git" }
  ]
}
composer require company/laravel-api-kit
php artisan vendor:publish --tag=api-kit-config   # optional
php artisan vendor:publish --tag=api-kit-lang     # optional

The ServiceProvider and ApiResponse facade auto-register (package discovery).

Response shapes

Success:

{ "success": true, "message": "Data berhasil diambil", "data": {} }

Validation error (422):

{ "success": false, "message": "Validation failed", "errors": { "email": ["Email wajib diisi"] } }

Server error (500): { "success": false, "message": "Terjadi kesalahan pada server" } Unauthorized (401): { "success": false, "message": "Unauthorized" } Not found (404): { "success": false, "message": "Data tidak ditemukan" }

Usage

use Company\ApiKit\Facades\ApiResponse;

return ApiResponse::success($user, 'Data berhasil diambil');
return ApiResponse::error('Gagal memproses', 400);
return ApiResponse::validation(['email' => ['Email wajib diisi']]);
return ApiResponse::unauthorized();
return ApiResponse::forbidden();
return ApiResponse::notFound();
return ApiResponse::paginate(User::paginate());

Or via the controller trait:

use Company\ApiKit\Traits\HasApiResponse;

class UserController extends Controller
{
    use HasApiResponse;

    public function index()
    {
        return $this->respondPaginated(User::paginate());
    }
}

Throwing for business rules (no try/catch needed — the renderer formats it):

use Company\ApiKit\Exceptions\BusinessException;

throw new BusinessException('Saldo tidak mencukupi', status: 422);

Wiring global exception handling

Laravel 11 — bootstrap/app.php

use Company\ApiKit\ApiKit;

->withExceptions(function (Illuminate\Foundation\Configuration\Exceptions $exceptions) {
    ApiKit::handleExceptions($exceptions);
})

Laravel 10 — app/Exceptions/Handler.php

use Company\ApiKit\Exceptions\Concerns\InteractsWithApiExceptions;

class Handler extends ExceptionHandler
{
    use InteractsWithApiExceptions;

    public function register(): void
    {
        $this->renderApiExceptions();
    }
}

Configuration highlights

  • api_prefix — which routes get standardized JSON errors (default api).
  • include_code — add a machine-readable code (e.g. VALIDATION_FAILED) to error bodies.
  • keys — rename envelope keys for incremental legacy migration.
  • logging — 5xx are logged by default; 4xx are not.
  • Messages live in publishable lang files (id, en). Set app.locale or edit after publish.

Testing

composer install
composer test

Built with Pest + Orchestra Testbench.