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

Dingo Api Custom Laravel Package

saritasa/dingo-api-custom

Saritasa's Dingo API Custom package extends Dingo API for Laravel projects with Saritasa-specific conventions, helping standardize API routing, responses, and integration points while reducing repetitive setup for Dingo-based services.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a thin set of opinionated overrides for dingo/api — it does not add a new API layer, it rewires a handful of Dingo's container bindings so that responses, exceptions and transformers behave the way Saritasa's other packages and Laravel project templates expect. Adopt it only if you are already running Dingo/Api and want its defaults aligned, not as a reason to pull Dingo in.

What changed in 3.0.0: Laravel 11 support. That is the whole changelog, but it is a major bump, so treat it as a constraint break rather than a feature: the package now targets Laravel 11 (PHP 8.2+), and the 2.x line is the one that supports older Laravel majors. If you are on Laravel 8–10 you stay on 2.x; if you are upgrading a project to Laravel 11 you have to move to 3.x and re-verify everything below. There is still no signal that this package will track Laravel 12, so the "will I have to vendor a fork?" question is deferred, not answered.

Start with the constraint audit rather than the install:

composer show saritasa/dingo-api-custom --all   # inspect requires/conflicts/replaces

What you are looking for in that output:

  • Which dingo/api version constraint 3.0.0 pins. Dingo itself has not moved quickly, so the Laravel 11 support here almost certainly comes with a specific dingo tag — confirm it is a real tagged release and not a dev branch.
  • Whether it declares replace/conflicts against other Saritasa packages.
  • The exact illuminate/* bounds — "Laravel 11 support" usually means "Laravel 11 only", not "11 and below".

Install it, then read the service provider before writing any code:

composer require saritasa/dingo-api-custom:^3.0
php artisan vendor:publish --provider="Saritasa\DingoApiCustom\Providers\DingoApiCustomServiceProvider"

(If the publish tag is not config, list tags with php artisan vendor:publish and pick the package's entry.) The provider's register()/boot() methods are the entire contract of the package — every behaviour it changes is visible there as an $this->app->extend(...) or $this->app->singleton(...) call. Note down which Dingo contracts it rebinds; those are the seams you will interact with later.

First use case: make a validation failure on an API route return a predictable JSON envelope instead of a redirect or an HTML error page. With Dingo plus these customizations the flow is:

// routes/api.php (Dingo router, not Laravel's)
$api->version('v1', function ($api) {
    $api->post('users', 'App\Api\V1\Controllers\UserController@store');
});

// app/Api/V1/Requests/StoreUserRequest.php
class StoreUserRequest extends FormRequest
{
    public function authorize(): bool { return true; }

    public function rules(): array
    {
        return ['email' => 'required|email', 'name' => 'required|string'];
    }
}

Then curl -X POST /api/users -d '{}' -H 'Accept: application/json' should yield a 422 with a machine-readable body rather than a stack trace. If you get HTML, the customization provider is not overriding Dingo's exception handler — check app()->getLoadedProviders() in tinker and provider order (see Gotchas).

Verify the Dingo stack itself is healthy first:

php artisan api:routes      # Dingo's route list — must populate
php artisan api:cache       # or explicitly confirm you are NOT using it

If api:routes is empty, the package is not the problem — your config/api.php and route registration are, and no amount of customization will fix that.

Implementation Patterns

Override, don't fork. The package works by swapping Dingo's contract bindings. When you need project-specific behaviour beyond what it provides, extend the same seams rather than editing vendor code — your provider boots after the package provider (register it later in config/app.php or rely on discovery order) so your binding wins:

// app/Providers/ApiServiceProvider.php
public function register(): void
{
    $this->app->extend(
        \Dingo\Api\Contract\Debug\ExceptionHandler::class,
        fn ($handler, $app) => new App\Api\ExceptionHandler($handler->getResponseFactory())
    );
}

Response transformation layer. Dingo's Transformer\Factory plus binding is the normal path; keep the customization package's serializer defaults in mind so your transformer output matches what the package normalizes (e.g. whether a top-level data key exists):

$api->version('v1', function ($api) {
    $api->get('users/{id}', [
        'as' => 'api.users.show',
        'uses' => 'App\Api\V1\Controllers\UserController@show',
    ]);
});

// controller
public function show(int $id)
{
    return $this->response->item(User::findOrFail($id), new UserTransformer());
}

Mixing $this->response->item() (Dingo) with return new UserResource(...) (Laravel) in the same controller is the most common source of "the shape changed after I added one endpoint" bugs.

Errors as a first-class contract. The main day-to-day value of a customization package like this is a stable error payload. Centralise status mapping in one place rather than in each controller:

// App\Api\ExceptionHandler
protected function handleException(Exception $e): Response
{
    return match (true) {
        $e instanceof \Illuminate\Validation\ValidationException
            => $this->response->array(['message' => 'invalid', 'errors' => $e->errors()])->setStatusCode(422),
        $e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException
            => $this->response->errorNotFound(),
        default => parent::handleException($e),
    };
}

Auth and middleware (Laravel 11 form). Dingo routes use Dingo's own middleware aliases (api.auth, api.throttle), which are registered separately from Laravel's auth. On Laravel 11 there is no app/Http/Kernel.php by default, so the aliases you used to put in Kernel::$routeMiddleware now go in bootstrap/app.php:

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'api.auth' => \Dingo\Api\Http\Middleware\Auth::class,
        'api.throttle' => \Dingo\Api\Http\Middleware\RateLimit::class,
    ]);
})

Make sure those aliases agree with Dingo's config/api.php middleware list — otherwise an endpoint looks protected but isn't.

Versioned routing is the natural home for package customizations. Put all version-scoped concerns (middleware, throttle, transformers) inside the $api->version() callback and keep cross-cutting ones in config/api.php. That way a v2 can be introduced without touching the override layer.

Testing. Use Dingo's dispatcher for internal API calls and plain $this->json() for HTTP-level tests:

$this->json('POST', '/api/users', [])->assertStatus(422)->assertJsonPath('message', 'invalid');

// internal call, bypasses HTTP layer
$response = app(\Dingo\Api\Dispatcher::class)->be($user)->post('users', $payload);

Test the error envelope explicitly — that is the part this package changes and the part least covered by Dingo's own suite.

Gotchas and Tips

  • 3.0.0 is a constraints release, not a feature release. One line of changelog ("Laravel 11 support") behind a major version bump. Expect the illuminate/* and dingo/api bounds to have moved and older-Laravel support to be gone. Pin ^2.0 on Laravel 8–10 projects and ^3.0 on Laravel 11; do not let composer require silently rewrite your framework version.
  • Verify the Laravel 11 support actually boots. A single-purpose compatibility release with no detail is exactly the kind of release where a Illuminate\Foundation\Application::version() check or a removed kernel method was missed. Smoke-test the three responses (404/422/500) before you plan any feature work on top of it.
  • Dingo itself is the bigger liability. Dingo/Api's maintenance cadence is slow, and it duplicates Laravel's own routing/response stack — on Laravel 11 that duplication is more friction, not less. If you are choosing today, Laravel 11's native api routes + FormRequest + JsonResource cover almost everything this package is smoothing over. Adopt only on inherited Dingo projects.
  • Provider order matters. If your provider also extends Dingo contracts, register it after DingoApiCustomServiceProvider, or your bindings get clobbered. Discovery order follows composer.json order — use explicit providers entries in bootstrap/providers.php (Laravel 11's replacement for the providers key in config/app.php) when order is load-bearing.
  • php artisan config:cache after any config change. Dingo reads config/api.php heavily; a stale cached config is the #1 cause of "my customization stopped working in staging." Laravel 11's optimize command caches config and routes together — clear it, don't fight it.
  • APP_DEBUG=true changes the error shape. Debug mode leaks traces through the handler you just customized. Assert on the production shape in tests (config(['app.debug' => false])).
  • Route caching is not supported the same way. php artisan route:cache does not see Dingo routes; use php artisan api:cache if you need it, and remember it must be cleared on every deploy (api:cache → api:clear). Laravel 11's php artisan optimize will not do this for you.
  • Namespace/version drift is more likely across a major bump. If you see Class "Saritasa\DingoApiCustom\..." not found after upgrading to 3.x, the provider/directory layout may have changed — confirm against the provider FQCN in the package's composer.json extra.laravel.providers before touching your own config.
  • Extension points are narrow by design. The package's value is its defaults, not its API. Anything project-specific belongs in your own provider, bound to Dingo contracts — do not patch vendor files, because a package that ships one release per Laravel major guarantees you will be re-applying patches by hand forever.
  • Upgrade/onboarding checklist: composer why saritasa/dingo-api-custom → confirm Laravel ↔ package major line matches → api:routes → hit a 404, a 422 and a 500 → confirm all three use the same envelope → only then start feature work.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
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