laravel-api-crud maintained by david-chamling
Laravel API CRUD Generator – Fast, Flexible, and Extensible API Scaffolding
A powerful Laravel package that generates complete CRUD API scaffolding with a single Artisan command.
🚀 Features
- 🔧 Single-command CRUD scaffolding
- 🧩 Built-in lifecycle hooks (before/after store/update)
- 🚪 Custom route macros
- 🔍 Advanced search and filtering
- 📄 Pagination support
- 🛡️ Request validation
- 🎯 Resource transformation
- 👤 Automatic user tracking (created_by / updated_by)
- ⚙️ Customizable stubs
✅ Requirements
- PHP >= 8.1
- Laravel >= 9.x
📚 Learn by Example
Want to see it in action? Check out this step-by-step guide where we build a complete Blog API using this package:
👉 Read the full step-by-step tutorial on Medium
📦 Installation
Install via Composer:
composer require david-chamling/laravel-api-crud
(Optional) Publish stub files for customization:
php artisan vendor:publish --tag=crud-stubs
⚡ Basic Usage
Generate full CRUD scaffolding for a model:
php artisan make:crud Product
This will generate:
- Controller
- Service class
- Form requests
- API resource
- Model
- Migration
- Routes
Define routes in your routes/api.php:
Route::crudResource('products', ProductController::class);
✅ Note: The
crudResource()macro is automatically registered by the package.
🔒 Request Validation
For security and data integrity, you must define complete validation rules in your generated request classes.
⚠️ Important: This CRUD system only uses validated data. If you forget to define rules in your request classes, fields like
name,price, etc., will be empty or missing from your controller — even if you pass them in the request.
Define validation rules in your generated request classes:
// StoreProductRequest.php
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
'category_id' => 'required|exists:categories,id'
];
}
🧩 Model Configuration
Ensure your model’s $fillable property includes all the fields:
// Product.php
protected $fillable = [
'name',
'price',
'category_id',
// Add additional fields here
];
📘 Generated Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /products | Paginated list |
| GET | /products/all | Get all records |
| GET | /products/count | Count total items |
| GET | /products/{id} | Get single record |
| POST | /products | Create new record |
| PUT | /products/{id} | Update record |
| DELETE | /products/{id} | Delete record |
| GET | /products/featured | Custom endpoint |
🔍 Advanced Query Parameters
Customize search, filters, and pagination in your controller:
protected array $searchableColumns = ['name', 'description'];
protected array $searchableRelations = ['category' => ['name']];
protected int $paginationNumber = 15;
Examples:
GET /products?search=keyboard
GET /products?filter[status]=active
GET /products?sort_by=price&sort_order=desc
GET /products?with=category&fields=id,name
GET /products?per_page=20&page=2
🪝 Lifecycle Hooks
Override lifecycle hooks in your custom CRUD service:
public function beforeStore(array $data, Request $request): array
{
$data['slug'] = Str::slug($data['name']);
return $data;
}
public function afterStore(Model $model, Request $request): void
{
// sending Notification, Sms, Creating logs, Storing into relational table
// example:
ActivityLog::create([
'user_id' => $request->user()->id,
'action' => 'store',
'model_id' => $model->id,
'changes' => $model->getChanges(),
]);
if ($model->wasChanged('status')) {
Notification::send(
$model->assignedUsers,
new StatusUpdatedNotification($model)
);
}
}
🔁 API Responses
Use the built-in response helper for consistency:
use DavidChamling\LaravelApiCrud\Utilities\ApiResponse;
return ApiResponse::success($data); // 200 OK
return ApiResponse::created($newModel); // 201 Created
return ApiResponse::error('Something went wrong'); // 400/500 Error
return ApiResponse::validationError($errors); // 422 Unprocessable
🧱 Customization
After publishing stubs, you can customize all generated files:
stubs/crud-controller/
├── controller.stub
├── model.stub
├── service.stub
├── store-request.stub
├── update-request.stub
├── resource.stub
Modify these to fit your code style or architecture.
💡 Example Controller
use DavidChamling\LaravelApiCrud\Controllers\CrudController;
use DavidChamling\LaravelApiCrud\Utilities\ApiResponse;
class ProductController extends CrudController
{
protected array $searchableColumns = ['name', 'sku'];
protected array $searchableRelations = [
'category' => ['name'],
'manufacturer' => ['name'],
];
public function __construct()
{
parent::__construct(
model: Product::class,
storeRequest: StoreProductRequest::class,
updateRequest: UpdateProductRequest::class,
simpleResource: ProductResource::class,
detailedResource: ProductDetailResource::class,
serviceClass: ProductCrudService::class
);
}
public function featured()
{
$products = $this->model::featured()->get();
return ApiResponse::success(ProductResource::collection($products));
}
}
🛠️ Support
Having issues or suggestions? Open an issue on GitHub:
📝 License
MIT Licensed. See LICENSE.
🤝 Contributing
Pull requests and suggestions are welcome! Feel free to open issues for bugs or enhancements.