mehedi8gb / api-crudify
Automate CRUD operations for Laravel APIs.
Requires
- php: ^8.2
- andreaselia/laravel-api-to-postman: ^2.1.0
- cviebrock/eloquent-sluggable: ^12.0.0
- laravel/framework: 12.*
- spatie/laravel-package-tools: ^1.16.4
Requires (Dev)
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- phpunit/phpunit: ^11.5
- dev-main
- v4.2.1
- v4.2.0
- v4.1.0
- v4.0.1
- v3.0.2
- 2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.1.91
- v1.1.72
- v1.1.71
- v1.1.70
- v1.1.60
- v1.1.53
- v1.1.52
- v1.1.51
- v1.1.9
- v1.1.6
- v1.1.5
- v1.1.4
- v1.1.3
- v1.1.2
- v1.1.0
- 1.0.0
- dev-release/v4.2.1
- dev-release/v4.2.0
- dev-main_4.1.0
- dev-main_add-support-Laravel-v11
- dev-main_add-support-Laravel-v10
- dev-mehedi8gb-update-composer.json
- dev-mehedi8gb-patch-2
- dev-mehedi8gb-patch-1
- dev-master
This package is auto-updated.
Last update: 2026-04-18 16:35:44 UTC
README
Laravel API Engine for Scalable Query-Driven Applications
Api Crudify is a professional-grade Laravel package that automates generation of robust, scalable, and standardized API CRUD components. It enforces the Service-Repository design pattern and implements a Chain of Responsibility pipeline for complex API queries β filtering, sorting, relation loading, soft deletes, and pagination β all driven by query parameters.
π Key Features
- Standardized Architecture β Generates Controller, Service, Repository, Model, FormRequests, Resource, Migration, Factory, Seeder, and Feature Test in one command.
- Chain of Responsibility Query Pipeline β Modular, ordered handlers process every API request: SoftDelete β Relations β Filter β Sort β Pagination.
- Advanced Dynamic Filtering β Frontend-friendly
?q=shorthand plus low-level?where=and?orWhere=with relation traversal support. - Smart Relation Loading β Respects explicitly passed relations, model
$with, or Eloquent eager loads automatically. - Soft Delete Awareness β
?trashed=withor?trashed=onlyquery params built in. - Domain-Driven Design Ready β Full support for nested namespaces:
V1/Inventory/Product. - Auto-Restoration β Detects and restores any missing base classes on every
crudify:makerun. - Route Management β Automatically registers API routes and
usestatements. - Helper Utilities β Global helper functions for responses, caching, payload filtering, and more.
π¦ Installation
composer require mehedi8gb/api-crudify --dev
Run the installer to bootstrap all base classes and configure autoloading:
php artisan crudify:install
This command will:
- Copy all base classes, interfaces, and query handlers into your
app/directory - Add
app/Helpers/Helpers.phptocomposer.jsonautoload files - Run
composer dump-autoloadautomatically
π Usage
php artisan crudify:make {Name}
Examples
# Simple CRUD php artisan crudify:make Product # Versioned / domain-specific php artisan crudify:make V1/Inventory/Category # With Postman schema export php artisan crudify:make Product --export-api-schema
π Generated Components
| Component | Path |
|---|---|
| Controller | app/Http/Controllers/{Path}/{Name}Controller.php |
| Model | app/Models/{Path}/{Name}.php |
| Service | app/Services/{Path}/{Name}Service.php |
| Repository | app/Repositories/{Path}/{Name}Repository.php |
| Form Requests | app/Http/Requests/{Path}/{Name}StoreRequest.php & UpdateRequest.php |
| Resource | app/Http/Resources/{Path}/{Name}Resource.php |
| Migration | database/migrations/YYYY_MM_DD_create_{names}_table.php |
| Factory | database/factories/{Path}/{Name}Factory.php |
| Seeder | database/seeders/{Path}/{Name}Seeder.php |
| Feature Test | tests/Feature/{Path}/{Name}Test.php |
π Architecture Overview
Every generated CRUD follows a strict 3-layer architecture:
HTTP Request
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Controller β β HTTP only: validate, call service, return response
β (extends BaseController) β
ββββββββββββββββ¬βββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Service β β Business logic, orchestration
β (extends BaseService) β
ββββββββββββββββ¬βββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Repository β β Data access only, Eloquent queries
β (extends BaseRepository) β
ββββββββββββββββ¬βββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββ
β Query Pipeline β β Chain of Responsibility
β SoftDelete β Relations β β
β Filter β Sort β Pagination β
βββββββββββββββββββββββββββββββββββ
Real-World Example
Controller β HTTP only, no business logic:
final class ProductController extends BaseController { public function __construct( private readonly ProductService $service ) {} public function index(): JsonResponse { $collection = $this->service->getProductsCollection(); return $this->successResponse('Products retrieved successfully', $collection); } }
Service β orchestrates business logic:
class ProductService extends BaseService { public function __construct( protected ProductRepository $productRepository, protected Request $request ) { parent::__construct($productRepository, $request); } public function getProductsCollection(): array { $data = $this->productRepository->getProductsData(); return $this->prepareResourceResponse($data, ProductResource::class); } }
Repository β data access only:
class ProductRepository extends BaseRepository { public function __construct(Product $model, protected Request $request) { parent::__construct($model, $request); } public function getProductsData(array $with = ['category', 'tags']): array { return $this->handleApiQueryRequest($this->query(), $with); } }
β‘ Query Pipeline β Chain of Responsibility
Every API request through handleApiQueryRequest() passes through this ordered pipeline:
Builder + Request
β
βΌ
ββββββββββββββββββββ
β SoftDeleteHandlerβ ?trashed=with|only|default
ββββββββββ¬ββββββββββ
βΌ
ββββββββββββββββββββ
β RelationHandler β Explicit $with β model $with β Eloquent eager loads
ββββββββββ¬ββββββββββ
βΌ
ββββββββββββββββββββ
β FilterHandler β ?q= / ?where= / ?orWhere= / ?exclude= / ?operator=
ββββββββββ¬ββββββββββ
βΌ
ββββββββββββββββββββ
β SortHandler β ?sortBy= / ?sortOrder=asc|desc
ββββββββββ¬ββββββββββ
βΌ
ββββββββββββββββββββ
βPaginationHandler β ?page= / ?limit= / ?limit=all
ββββββββββ¬ββββββββββ
βΌ
{ meta, data }
π Query Parameter Reference
Filtering
| Parameter | Description | Example |
|---|---|---|
?q= |
Frontend-friendly shorthand filter | ?q=title=phone |
?where= |
Direct column filter | ?where=status,active |
?orWhere= |
OR column filter | ?orWhere=type,admin |
?operator= |
Comparison operator | ?operator== or ?operator=like |
?exclude= |
Exclude a specific value | ?exclude=status,deleted |
Relation filtering via ?where=:
?where=with:category,name,Electronics
?where=with:category.parent,name,Tech
Frontend shorthand ?q= with pipe-separated conditions:
?q=title=phone|status=active
?q=category.name=Electronics
Complex nested relational query conditions:
?q=posts.category.child.status=active
?q=posts.createdBy.userId=10
?or=true converts multiple ?q= conditions to orWhere:
?q=title=phone|brand=apple&or=true
Sorting
| Parameter | Default | Example |
|---|---|---|
?sortBy= |
created_at |
?sortBy=price |
?sortOrder= |
desc |
?sortOrder=asc |
Safe against SQL injection β column existence is verified against the schema before applying. Skipped if the builder already has an
orderByapplied.
Soft Deletes
| Parameter | Behaviour |
|---|---|
?trashed=with |
Include soft-deleted records |
?trashed=only |
Return only soft-deleted records |
| (omitted) | Exclude soft-deleted records (default) |
Pagination
| Parameter | Default | Description |
|---|---|---|
?page= |
1 |
Current page |
?limit= |
10 |
Records per page |
?limit=all |
β | Returns all records, no pagination |
Response structure:
{
"meta": {
"page": 1,
"limit": 10,
"total": 245,
"totalPage": 25
},
"data": [ ... ]
}
Relation Loading
Relations are resolved in this priority order:
- Explicit
$witharray passed tohandleApiQueryRequest() - Model-level
$withproperty - Eloquent registered eager loads via
getEagerLoads()
π§° Helper Functions
Global utility functions available after install:
| Function | Description |
|---|---|
sendSuccessResponse($message, $data, $status) |
Standardized JSON success response |
sendErrorResponse($exception, $status) |
Standardized JSON error response with environment-aware detail |
validationException($payload, $key) |
Throw a ValidationException from array or string |
filterPayload($data, $allowedKeys) |
Keep only allowed keys from an array |
cacheQuery($query, $method, $args, $ttl) |
Execute and cache a query with tag-based invalidation |
generateCacheKey($builder, $request, $tenantId) |
Generate deterministic cache key from query state |
getCreatedAtColumn($builder|$model) |
Resolve model's CREATED_AT column safely |
getResourceClass($model) |
Auto-resolve {Model}Resource class or fallback to DefaultResource |
deepMerge($original, $new) |
Deep array merge with force-replace support |
processNestedArray($existing, $payload) |
Merge and deduplicate nested arrays by id |
convertStatus($status) |
Convert boolean to 1/0 |
generateUniqueNumber($prefix) |
Generate a unique prefixed identifier |
getFormatedDate($carbon) |
Human-readable date with diff: "2 days ago (14th April at 08:21 AM in 2025)" |
βοΈ Base Classes Installed
After crudify:install, the following are placed in your app/ directory:
app/
βββ IContracts/
β βββ Repositories/ (IRepository, IReadRepository, IWriteRepository)
β βββ Services/ (IService, IReadService, IWriteService)
βββ Repositories/V1/BaseRepository.php
βββ Services/V1/BaseService.php
βββ Models/Model.php
βββ Helpers/Helpers.php
βββ Core/
β βββ Query/
β β βββ HandleApiQueryRequest.php
β β βββ Contracts/IQueryHandler.php
β β βββ Handlers/
β β βββ AbstractQueryHandler.php
β β βββ Core/
β β β βββ FilterHandler.php
β β β βββ PaginationHandler.php
β β β βββ RelationHandler.php
β β β βββ SoftDeleteHandler.php
β β β βββ SortHandler.php
β β βββ Optimization/CacheHandler.php
β βββ ClientQuery/ (mirror of Query for client-facing APIs)
βββ Http/Resources/DefaultResource.php
π Changelog
Please see CHANGELOG for recent changes.
β¨ Credits
π License
The MIT License (MIT). Please see License File for more information.