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 Core Bundle Laravel Package

kami/api-core-bundle

kami/api-core-bundle is a reusable API core package for PHP applications, bundling common building blocks for routing, response formatting, validation, and error handling. It helps teams standardize endpoints, reduce boilerplate, and ship consistent, maintainable APIs faster.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm it is actually a Laravel package before anything else. The name says "bundle" (Symfony terminology) but the description says Laravel. Read composer.json's require block first: if it pulls symfony/framework-bundle and registers via config/bundles.php, it is a Symfony package with Laravel branding and you should stop. If it requires illuminate/support and ships a ServiceProvider, proceed.

composer require kami/api-core-bundle

With 0 stars and 0 dependents there is no install evidence on current Laravel versions, so run this on a scratch branch. If Composer resolves against Laravel 10/11 and PHP 8.2/8.3 in the constraint block, note that. If it's pinned to an old major, treat that as an adoption blocker, not something to work around with --ignore-platform-reqs.

Where to look first, in this order:

  1. The service provider (src/*ServiceProvider.php) — this tells you what is registered, whether config is publishable, and whether anything is bound conditionally. It is the public API surface.
  2. The published config — run php artisan vendor:publish --tag=config (or whatever tag it exposes) and read the config file. Every knob you can turn lives here. This replaces the README, which for a 0-star package is likely stale.
  3. The response envelope class / base controller — this defines the JSON shape every endpoint will return. Read it before writing endpoints, because the shape becomes your client contract.
  4. The exception handler / renderer — this is the highest-risk code path in the package (see Gotchas).

First use case: make one endpoint return a canonical success and a canonical error. The core value proposition is a uniform envelope. Prove it with the smallest possible endpoint plus a deliberate failure:

// routes/api.php
Route::get('/ping', fn () => ['pong' => true]);
Route::get('/boom', function () {
    throw new \InvalidArgumentException('boom', 422);
});

Curl both. You want:

// 200
{ "data": { "pong": true }, "meta": { ... } }

// 422
{ "error": { "code": "...", "message": "boom" } }

If /boom returns an HTML error page or Laravel's default {"message": ...} shape, the exception renderer isn't wired — that's your first debugging task, and if it doesn't work you've saved yourself a week.

Implementation Patterns

Subclass the base controller once, app-wide. Don't extend Kami\...\BaseController directly in each controller — wrap it:

namespace App\Http\Controllers;

use Kami\ApiCoreBundle\Http\BaseApiController as Base;

abstract class ApiController extends Base
{
    // app-wide helpers: current user, tenant id, custom meta in envelope
}

Now a package upgrade only touches one file, and swapping the package later is a contained diff.

Throw domain exceptions, map them centrally. The package exists to convert exceptions into JSON. Keep controllers thin and let the mapping do the work. If the config exposes an exception→status map, use it. If it doesn't, add a Handler::render override in your app that delegates to the package for the cases it handles and adds yours:

// app/Exceptions/Handler.php
public function render($request, Throwable $e)
{
    if ($e instanceof \App\Exceptions\DomainException) {
        return response()->json([
            'error' => ['code' => $e->errorCode(), 'message' => $e->getMessage()],
        ], $e->status());
    }
    return parent::render($request, $e); // package handles the rest
}

The win: every error shape in the app is greppable in one file, and you can add codes without touching endpoints.

Use the validation helpers, but own the failure shape. If the package provides a request-validation trait or FormRequest base, use it so validation failures return the same error envelope as thrown exceptions. Add one test asserting the 422 shape — validation failures are the most common client-visible error and the most likely to drift on upgrade.

Paginate through the package's contract. Whatever the pagination meta looks like (meta.current_page, links.next, etc.), generate it from the package helper rather than hand-rolling LengthAwarePaginator JSON. Then write a single contract test that asserts the exact keys. That test is your upgrade tripwire.

Wrap behind a thin adapter. For a package with no maintainer, don't let Kami\... types leak into 40 files:

namespace App\Api;

class Envelope
{
    public static function success(mixed $data, array $meta = []): array { /* delegate */ }
    public static function error(string $code, string $message, int $status = 400) { /* delegate */ }
}

Controllers and listeners talk to App\Api\Envelope. If the package dies or its envelope drifts, you patch one class.

Version-pin and lock. "kami/api-core-bundle": "1.2.3" — no ^. On a package with no release discipline, a caret range is a live grenade in your composer.json. Add it to your Laravel upgrade checklist: every laravel/framework bump requires re-running your contract tests against this package.

Gotchas and Tips

"Bundle" in the name is a red flag. Verify Laravel-native service providers before planning anything. A Symfony bundle with Laravel shims will fight your framework, and the effort to discover that is five minutes versus a month.

Debug mode will leak internals unless you check. Exception renderers that dump getTrace() or previous chain into the response will do it whenever APP_DEBUG=true. Read the renderer's production path explicitly. Set APP_DEBUG=false in staging and hit your /boom endpoint — if you see file paths or SQL, you've found a security issue in the package. Do not ship that.

Middleware order matters, and there is no recipe to place it. If the package registers global or route middleware via the service provider, and you also add your own auth/throttle middleware, the order in bootstrap/app.php (Laravel 11) or Kernel.php (10 and below) decides whether the response envelope wrapper runs before or after auth failures. Test with a 401: if it returns HTML, the exception renderer isn't catching auth exceptions because it's outside the middleware stack.

Published config overrides are shallow unless you use mergeConfigFrom. If the package's provider doesn't call mergeConfigFrom with a sensible default, publishing config means you now own every future config key. Compare: after publish, grep for config('kami' in the package src/ — any key missing from your published file falls back to the package default, which is fine. Any key the package reads with no default is a crash waiting on upgrade.

Zero dependents means zero field-proven upgrade paths. Budget the fork from day one: vendor it into packages/kami-api-core with a Composer path repository, or fork to your namespace. Do this before the first production deploy, not when a Laravel major lands and you find yourself maintaining someone else's unmaintained code under deadline.

The envelope is a client-facing contract, not an internal detail. Once two endpoints use it, SDKs and integrators depend on key names. Changing error.code to error.type later is a breaking API version. Pin the shape with a test that asserts the raw JSON, not just field-by-field — a removed key and a nulled key look identical to an assertion that only checks presence.

Validation error extraction is a known footgun. If the package formats validation errors, check the nested shape for field arrays: {"errors": {"email": ["required"]}} vs {"errors": {"email": "required"}}. The ValidationException message bag produces arrays; the formatter may flatten or nest inconsistently. Test with a request that fails two fields at once.

Testing is the only thing keeping this adoptable. With no community, write your own: one test per response type (success, validation failure, 404, 401, 500) asserting the exact shape, run against every Laravel minor you support. That suite is the actual value you get from the package — it turns boilerplate into a specification, and if the package regresses you'll know in CI rather than in a customer's SDK.

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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core