singlequote / laravel-api-resource
Installs: 1 023
Dependents: 0
Suggesters: 0
Security: 0
Stars: 5
Watchers: 2
Forks: 1
Open Issues: 0
Requires
Requires (Dev)
- laravel/pint: ^1.15
- dev-main
- 2.2.7
- 2.2.6
- 2.2.5
- 2.2.4
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.14
- 2.1.13
- 2.1.12
- 2.1.11
- 2.1.10
- 2.1.9
- 2.1.8
- 2.1.7
- 2.1.6
- 2.1.5
- 2.1.4
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.24
- 2.0.23
- 2.0.22
- 2.0.21
- 2.0.20
- 2.0.19
- 2.0.18
- 2.0.17
- 2.0.16
- 2.0.15
- 2.0.14
- 2.0.13
- 2.0.12
- 2.0.11
- 2.0.10
- 2.0.9
- 2.0.8
- 2.0.7
- 2.0.6
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.1.18
- 1.1.17
- 1.1.16
- 1.1.15
- 1.1.14
- 1.1.13
- 1.1.12
- 1.1.11
- 1.1.10
- 1.1.9
- 1.1.8
- 1.1.7
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.0
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- dev-fix/scope-sequence
- dev-fix/return-success-closure
This package is auto-updated.
Last update: 2025-09-17 09:53:25 UTC
README
A practical Laravel package designed to streamline API development by automating resource generation and providing a powerful, out-of-the-box filtering system.
This package accelerates your workflow with two core features:
- Rapid Scaffolding: Use the
php artisan make:api-resource
command to intelligently generate a full set of API files (Controller, Actions, Requests, and Resource) from your existing models. - Powerful Filtering: Equip your API endpoints with a comprehensive set of filters from the moment you install it. Sort, search, and filter resources with ease without any initial setup.
Table of Contents
Installation & Setup
1. Install the package via Composer:
composer require singlequote/laravel-api-resource
2. (Optional) Publish Files:
You can publish the configuration and stub files to customize the package's behavior and generated file templates.
Publish the config file:
php artisan vendor:publish --tag=laravel-api-resource-config
Publish the stub files:
php artisan vendor:publish --tag=laravel-api-resource-stubs
Usage
1. Generating a Full API Resource
Use the make:api-resource
Artisan command to generate all the necessary files for a model's API endpoint.
php artisan make:api-resource User
This single command creates the following file structure, ready for you to add your business logic:
App/Http/Controllers
└── Api/UserController.php
App/Actions/Users
├── DeleteUserAction.php
├── IndexUserAction.php
├── ShowUserAction.php
├── StoreUserAction.php
└── UpdateUserAction.php
App/Http/Requests/Users
├── IndexUserRequest.php
├── ShowUserRequest.php
├── StoreUserRequest.php
└── UpdateUserRequest.php
App/Http/Resources
└── UserResource.php
Finally, add the generated route to your routes/api.php
file:
use App\Http\Controllers\Api\UserController; Route::apiResource('users', UserController::class);
2. Using the API Filters
To enable the powerful filtering capabilities, simply add the HasApi
trait to your model.
use Illuminate\Database\Eloquent\Model; use SingleQuote\LaravelApiResource\Traits\HasApi; class User extends Model { use HasApi; // ... }
You can now use a wide range of query parameters to filter your API results directly from the URL. See the API Filtering Reference below for a full list of available methods.
3. Customizing the Resource Response
The package provides helpers to easily customize your JSON response. For instance, you can use the ApiPolicyService
to automatically include the results of your model's policies.
In your UserResource.php
:
use SingleQuote\LaravelApiResource\Service\ApiPolicyService; use Illuminate\Http\Request; public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, // ... 'policies' => ApiPolicyService::defaults($this->resource, ['sendInvite']), ]; }
API Filtering Reference
All examples use the Ziggy package for clean URL generation. A manual URL example is provided for reference.
Helper | Value Type | Description |
---|---|---|
limit |
number |
Sets the number of results per page. |
search |
array |
Searches specified columns for a query. |
where |
array |
Adds a "where" clause to the query. |
orWhere |
array |
Adds an "or where" clause. |
whereIn |
array |
Filters by a column's value within an array. |
whereNotIn |
array |
Filters by a column's value not in an array. |
whereNull |
string |
Finds records where a column is NULL. |
whereNotNull |
string |
Finds records where a column is not NULL. |
has |
array |
Filters based on the existence of a relationship. |
doesntHave |
array |
Filters based on the absence of a relationship. |
whereRelation |
array |
Queries a relationship with a where condition. |
with |
array |
Eager loads relationships. |
withCount |
array |
Counts the results of a given relationship. |
select |
array |
Selects specific columns to return. |
orderBy |
string |
Sorts the results in ascending order. |
orderByDesc |
string |
Sorts the results in descending order. |
limit
The default limit is 1000
. You can change this in the config file or override it per request.
axios.get(route('api.users.index', { limit: 100 })); // GET /api/users?limit=100
search
Search for a query within specified columns. Use *
to search all fillable columns.
axios.get(route('api.users.index', { search: { fields: ['name', 'email'], query: "john" } })); // GET /api/users?search[fields][0]=name&search[fields][1]=email&search[query]=john
where
Add "where" clauses. You can also provide an operator (gt
, lt
, sw
, etc.).
Operator | Shorthand |
---|---|
startsWith | sw |
endsWith | ew |
notContains | nin |
contains | in |
equals | eq |
notEqual | neq |
greater | gt |
greaterEquals | gte |
lesser | lt |
lesserEquals | lte |
axios.get(route('api.users.index', { where: { date_of_birth: { gt: "1995-01-31" } } })); // GET /api/users?where[date_of_birth][gt]=1995-01-31
whereIn / whereNotIn
Verifies that a column's value is (or is not) within a given array.
axios.get(route('api.users.index', { whereIn: { role: ['admin', 'employee'] } })); // GET /api/users?whereIn[role][0]=admin&whereIn[role][1]=employee
whereNull / whereNotNull
Verifies that a column's value is NULL
or not NULL
.
axios.get(route('api.users.index', { whereNull: "email_verified_at" })); // GET /api/users?whereNull=email_verified_at
has / doesntHave
Limit results based on the existence of a relationship. You can also add nested conditions.
axios.get(route('api.users.index', { has: { roles: { whereIn: { id: [1, 2] } } } })); // GET /api/users?has[roles][whereIn][id][0]=1&has[roles][whereIn][id][1]=2
whereRelation
Query for a relationship's existence with a simple where
condition.
axios.get(route('api.users.index', { whereRelation: { roles: { name: 'admin' } } })); // GET /api/users?whereRelation[roles][name]=admin
with
Eager load relationships to avoid N+1 query problems.
axios.get(route('api.users.index', { with: { roles: { select: ['id', 'name'] } } })); // GET /api/users?with[roles][select][0]=id&with[roles][select][1]=name
withCount
Count the number of results from a relationship without loading them.
axios.get(route('api.users.index', { withCount: ['posts'] })); // GET /api/users?withCount[0]=posts
Note: To include the count in your response, you must manually add the posts_count
attribute to your resource's toArray
method.
// In app/Http/Resources/UserResource.php public function toArray(Request $request): array { return [ // ... other attributes 'posts_count' => $this->whenCounted('posts'), ]; }
select
Specify which columns to retrieve to keep responses lean.
axios.get(route('api.users.index', { select: ['id', 'name'] })); // GET /api/users?select[0]=id&select[1]=name
orderBy / orderByDesc
Sort the results by a given column, including columns on related models.
axios.get(route('api.users.index', { orderBy: 'roles.name' })); // GET /api/users?orderBy=roles.name
Custom Orderable Columns
To make custom columns (e.g., from withCount
or withSum
) sortable, add them to the $apiOrderBy
property on your model.
// In your Product.php model class Product extends Model { public array $apiOrderBy = [ 'articles_sum_price', // From a withSum query ]; }
Now you can sort by this custom column:
GET /api/products?orderBy=articles_sum_price
Contributing
Please see CONTRIBUTING.md for details.
Postcardware
You're free to use this package, but if it makes it to your production environment, we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.
Our address is: Quotec, Traktieweg 8c 8304 BA, Emmeloord, Netherlands.
Credits
License
The MIT License (MIT). Please see License File for more information.