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

Laravel Api Controller Laravel Package

phpsa/laravel-api-controller

phpsa/laravel-api-controller provides a reusable base controller for building RESTful APIs in Laravel. It simplifies common CRUD endpoints and standardizes JSON responses, reducing boilerplate so you can ship clean, consistent API controllers faster with less repetitive code.

View on GitHub
Deep Wiki
Context7

Getting Started

phpsa/laravel-api-controller gives you a base API controller and a base API resource that implement the boring 80% of a JSON CRUD endpoint: pagination, whitelisted filtering, sorting, relationship includes, sparse fieldsets, validation and authorization hooks.

Minimal setup:

  1. composer require phpsa/laravel-api-controller
  2. Generate a controller and extend the package base class instead of Laravel's:
    use Phpsa\LaravelApiController\Http\Api\Controller;
    
    class PostController extends Controller
    {
        protected $model = Post::class;
        protected $resource = PostResource::class; // optional
    }
    
  3. Register it like any resource route: Route::apiResource('posts', PostController::class);
  4. Your resource can extend Phpsa\LaravelApiController\Http\Api\Resource to inherit the response envelope/meta helpers.

Where to look first, in order:

  • The base Controller class and its concern traits — that's where index/show/store/update/destroy and the query-building live.
  • The Resource base class for the response shape (data/meta/links).
  • The package README's controller section for the exact property names your installed version expects ($allowedFilters, $allowedSorts, $allowedIncludes, $allowedFields, $defaultSort, $perPage, etc.).

First real use case: a read-only index endpoint. GET /api/posts?filter[status]=published&sort=-created_at&include=author&fields[posts]=id,title&per_page=25 works with only the $model property set — then you tighten it up with whitelists.

Implementation Patterns

Controller as declarative config. The idiomatic use is to keep the controller thin: declare the model, resource, and the whitelists, and let the base class do the work. Override index()/store() only when you genuinely diverge from the default behaviour.

Whitelist everything explicitly. Populate $allowedFilters, $allowedSorts, $allowedIncludes and $allowedFields per controller. Relationships that should be includable go in $allowedIncludes, and the base class eager-loads them, which is where most of the N+1 protection comes from.

Validation. Define rules on the controller for the standard actions, or override store/update to delegate to a FormRequest when rules get large or need Rule::unique()->ignore(). Keep the authorization in policies; the base controller calls into Laravel's gate/policy layer per action.

Custom guard per endpoint (new in v7.4.0). You can now declare a non-default guard on the controller and on the resource. Use it when your API is authenticated by a separate guard (e.g. api, or a token/tenant guard) rather than web:

protected $guard = 'api';

Set the same guard on the resource so authorization and any user-dependent output ($this->request->user($guard)) resolve consistently. This lets you have, say, an admin-only controller on the admin guard and public endpoints on the default guard in the same app.

Custom actions alongside the CRUD set. Add extra methods to the same controller (publish, archive, restore) so they inherit the same middleware, guard and policy conventions, then register explicit routes. Return the same resource type so clients see a consistent envelope.

Multi-controller reuse. Because behaviour is driven by properties, a pattern that works well is a thin abstract base per domain area (e.g. TenantController) that sets the guard and scoping, with concrete controllers extending it and only declaring $model/$resource.

Testing. Feature-test the endpoints with actingAs($user, 'api') matching the guard you configured, and assert on assertJsonStructure rather than exact payloads so resource changes don't churn your suite.

Gotchas and Tips

  • Silent whitelists. A query param that "does nothing" is almost always not whitelisted. Filters, sorts, includes and fields are all ignored unless declared. Make this your first debugging step.
  • Guard mismatch is the classic auth bug. $request->user() falls back to the default guard. If your route uses auth:api but the controller/resource has no $guard, policies will evaluate against the wrong user (or null). New in v7.4.0 you can set $guard on both the controller and the resource — set both, and ensure the guard exists in config/auth.php with a provider that maps to the model you're authorizing. Tests must use the same guard name in actingAs().
  • per_page needs a ceiling. Expose pagination but cap the maximum in config or by overriding the per-page resolution; otherwise a client can request 100k rows.
  • Sorting by alias vs column. Sorts are applied to real columns. If you want sort=name, make sure that's a column (or map aliases); relationship sorts need explicit joins, not just an allowed-sort entry.
  • Includes without eager loads. An allowed include that isn't constrained can pull huge graphs. Constrain with with() closures or restrict which includes are allowed per controller.
  • Route model binding vs IDs. The base actions work with bound models; for nested resources use scoped bindings so a child from another parent 404s instead of leaking data.
  • Status codes. destroy typically returns 204; if your front end expects a body, override it. Unauthorized access surfaces as 403 from policies while missing records are 404 — keep that distinction deliberate in tests.
  • Extension points to reach for first: override the action method (index, store, ...) for behavioural changes; override the model/resource resolution methods for multi-model or polymorphic controllers; publish the package config if you need to change pagination defaults or the response envelope rather than editing every controller.
  • Upgrade note: v7.4.0 is additive (custom guards in controller and resource) with no breaking changes — existing controllers keep the default guard behaviour, so adoption can be incremental, controller by controller.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
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