Installation
composer require rizkussef/laravel-crud-api
Publish the config:
php artisan vendor:publish --provider="RizkUssef\CrudApi\CrudApiServiceProvider"
Basic CRUD Endpoint
Define a model (e.g., Post) and generate a CRUD controller:
php artisan make:crud Post
This creates:
app/Http/Controllers/Api/V1/PostCrudController.phproutes/api.php:
Route::apiResource('posts', \App\Http\Controllers\Api\V1\PostCrudController::class);
First Request Test the API with:
curl -X GET http://your-app.test/api/v1/posts
Returns a paginated list of Post resources.
Resource class needed (uses JsonResource by default).with() in the controller.?filter[status]=published).Define Model & Relationships
// app/Models/Post.php
public function author()
{
return $this->belongsTo(User::class);
}
Extend the Controller
Override methods in PostCrudController:
protected function getQuery()
{
return Post::with('author')->where('status', 'published');
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
]);
return parent::store($validated);
}
Custom Filtering
Add a filter in app/Providers/CrudApiServiceProvider.php:
public function boot()
{
CrudApi::addFilter('posts', 'category', function ($query, $value) {
return $query->where('category_id', $value);
});
}
Use it via:
curl -X GET "http://your-app.test/api/v1/posts?filter[category]=1"
API Versioning: The package supports versioning via api/v1 routes by default. Extend with:
Route::prefix('api/v2')->group(function () {
Route::apiResource('posts', \App\Http\Controllers\Api\V2\PostCrudController::class);
});
Custom Responses
Override toArray() in your model or use a custom resource:
public function toArray()
{
return [
'id' => $this->id,
'title' => $this->title,
'slug' => Str::slug($this->title),
];
}
Authorization Use Laravel’s gates/policies within controller methods:
public function update(Request $request, $id)
{
$this->authorize('update', Post::findOrFail($id));
return parent::update($request, $id);
}
Testing Mock the controller in tests:
$response = $this->getJson('/api/v1/posts');
$response->assertStatus(200)->assertJsonStructure([...]);
Route Caching After adding new routes, clear the route cache:
php artisan route:clear
(Avoids Route [posts.store] not defined errors.)
Mass Assignment
The package does not auto-sanitize input. Always validate in store()/update():
$validated = $request->validate([
'title' => 'required',
'author_id' => 'exists:users,id',
]);
Relationship Loading Eager-loading is not automatic for nested relationships. Explicitly define:
protected function getQuery()
{
return Post::with(['author', 'comments.user']);
}
Pagination Defaults
The package uses Laravel’s default pagination (15 items). Override in getQuery():
return Post::paginate(10);
Enable Query Logging
Add to config/app.php:
'debug' => env('APP_DEBUG', true),
Check logs in storage/logs/laravel.log for raw queries.
Filter Validation
Filters are not validated by default. Add middleware or use Laravel’s Rule:
CrudApi::addFilter('posts', 'status', function ($query, $value) {
$query->where('status', $value);
return $query;
});
Custom Actions Add methods to the controller and define routes:
// Controller
public function publish($id)
{
$post = Post::findOrFail($id);
$post->update(['status' => 'published']);
return response()->json(['message' => 'Published!']);
}
// Route
Route::put('posts/{id}/publish', [PostCrudController::class, 'publish']);
Dynamic Fields
Use fillable or guarded in the model, but always validate in the controller.
Event Hooks
Listen for CRUD events in EventServiceProvider:
CrudApi::on('posts.created', function ($post) {
// Send notification, etc.
});
API Documentation Integrate with Laravel API Docs or Postman by documenting:
/api/v1/posts?filter[field]=value&include=relationshipsPOST/PUT.How can I help you explore Laravel packages today?