Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Toolkit Laravel Package

bluebeetle/api-toolkit

Bluebeetle API Toolkit gives Laravel developers a consistent foundation for building JSON APIs, bundling reusable response formatting, pagination, filtering, and error handling so endpoints stay predictable and teams write less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin

composer require bluebeetle/api-toolkit
# pin it — 0 dependents means you are the QA team
composer require bluebeetle/api-toolkit:^1.0 --with-all-dependencies

Check composer.json constraints before anything else: the supported PHP/Laravel matrix tells you more about production risk than the README does. With 14 stars and zero dependents, assume the package was extracted from one agency's internal projects and has only been exercised against their stack.

Publish and read, in this order

php artisan vendor:publish --provider="BlueBeetle\ApiToolkit\ApiToolkitServiceProvider"
php artisan vendor:publish --tag=api-toolkit-config   # if tags differ, list them: php artisan vendor:publish
  1. config/api-toolkit.php — this is the actual API surface. Every key is a behavior you can turn on/off; read it before writing code.
  2. The service provider (vendor/bluebeetle/api-toolkit/src/...ServiceProvider.php) — shows bindings, macros, middleware registration, and whether it auto-discovers.
  3. src/Http/ — base controller/trait and response helpers.
  4. src/Exceptions/ — how it hooks into the exception handler.

Skip the README's happy path until you've done step 3. Small packages usually have accurate code and stale docs.

First use case: convert one endpoint, not ten

Pick a single existing GET resource endpoint and put it behind the toolkit's response envelope and exception rendering. Add a contract test immediately:

it('returns the toolkit envelope', function () {
    $this->getJson('/api/v1/users')
        ->assertOk()
        ->assertJsonStructure([
            'data' => [['id', 'name']],
            'meta' => ['current_page', 'per_page', 'total'],
        ]);
});

That snapshot is your regression alarm for every future upgrade. Do this before touching auth, filtering, or validation — those are where the package's opinions collide with yours.

Implementation Patterns

Extend the base controller/trait rather than calling helpers ad hoc

If the package ships a base ApiController (or a RespondsWithJson trait), inherit it once and make your own App\Http\Controllers\Api\ApiController the parent for the whole api route group. Then a future swap — or a fork — is one file, not eighty.

abstract class ApiController extends \BlueBeetle\ApiToolkit\Http\Controller
{
    // project-wide tweaks live here, nowhere else
}

Keep the envelope in one place and test it as a contract

The whole value proposition of an API toolkit is a uniform { data, meta, errors } shape. Enforce it with a shared test helper (assertApiSuccess() / assertApiError()) used by every feature test. If you hand-roll response()->json() anywhere, the envelope drifts within a sprint.

Wire exception rendering at the framework boundary

Laravel 11+ (bootstrap/app.php):

->withExceptions(function (Exceptions $exceptions) {
    // register the toolkit's renderables / handler here
})

Laravel 10 and below: App\Exceptions\Handler::register(). Then assert both a 422 validation failure and a thrown 500 return the same error shape — this is the single most common integration bug with response-envelope packages.

Filters, sorting, pagination: whitelist in config, never trust the query string

Typical pattern — a trait on the query builder plus a config array of allowed fields:

// config/api-toolkit.php
'filters' => ['users' => ['name', 'email', 'created_at']],
'sorting' => ['users' => ['name', 'created_at']],
'pagination' => ['max_per_page' => 100],

Validate incoming ?sort= / ?filter[]= against those arrays in a FormRequest, then hand off to the toolkit. If the package doesn't enforce a whitelist itself (many don't), a client can reach orderBy with arbitrary column names — treat this as your responsibility, not the package's.

Pair with Eloquent API Resources and FormRequests

Let the toolkit own the envelope; let Resources own the payload; let FormRequests own the input contract. Keeping those three responsibilities separate is what makes the package cheap to remove later.

Roll out incrementally across the route group

Route::middleware(['api', 'throttle:api', 'auth:sanctum'])
    ->prefix('v1')
    ->group(base_path('routes/api/v1.php'));

Add the toolkit's middleware (request-id, force-JSON, etc.) to the api group in bootstrap/app.php so new routes inherit it automatically. Version the prefix (v1) from day one — envelope changes are breaking changes, and you'll want somewhere to put the next one.

Gotchas and Tips

  • Treat the dependency as unstable. 0 dependents, 14 stars, one maintainer. Pin to an exact tag (1.2.3, not ^1.2), commit composer.lock, and read the diff between tags before bumping. A minor release from a single-maintainer package is a breaking release until proven otherwise.
  • Verify the release you're actually installing. The listed release date (2026-10-20) is ahead of the current date — check Packagist for real tags versus dev-main, and prefer a tagged version over a branch alias.
  • Config caching bites. After editing config/api-toolkit.php or the related .env keys, run php artisan config:clear locally and remember that config:cache in deploy will freeze whatever was there at build time.
  • Middleware ordering matters more than usual. If the toolkit forces JSON responses, register it before auth middleware, otherwise unauthenticated requests can still redirect to a login route and your mobile client gets HTML.
  • Exception handler API drifted in Laravel 11. If the README targets Laravel 10, the registration snippet won't apply. Read src/ and register renderables manually rather than copy-pasting.
  • Pagination caps: check whether per_page is clamped. If not, a client asking for per_page=100000 will happily serialize your whole table.
  • Don't edit vendor/. Use the published config, rebind interfaces in your own AppServiceProvider, or subclass the base controller. Everything you need should be reachable through those three extension points; if it isn't, that's a signal the package won't survive your roadmap.
  • Debugging checklist: php artisan route:list --path=api (is the middleware attached?), php artisan about (config loaded?), vendor/bluebeetle/api-toolkit/src (what does the method actually do?), and log the rendered exception to confirm the toolkit — not Laravel's default handler — produced the output.
  • Have an exit plan. The package is MIT and small. If maintenance stalls, forking or inlining the response/exception layer is a day's work — but only if you kept it behind your own base controller. That architectural discipline is the real takeaway, not the package itself.
  • CI matrix: add a job against the lowest Laravel version in the package's composer.json constraint. With this little downstream usage, you are the compatibility testing.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core