Weave Code
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

Api Crudify Laravel Package

mehedi8gb/api-crudify

Laravel package that generates standardized API CRUD (controller/service/repository/resources/requests/tests) and a query-driven pipeline for relations, filters, sorting, soft deletes, and pagination via URL params. Supports DDD namespaces and auto route/setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the package:

    composer require mehedi8gb/api-crudify --dev
    php artisan crudify:install
    

    This copies base classes to app/ and sets up autoloading.

  2. Generate your first CRUD:

    php artisan crudify:make Post
    

    This creates a full stack: Controller, Service, Repository, Model, Requests, Resource, Migration, Factory, Seeder, and Test.

  3. Test the API:

    • Run migrations: php artisan migrate
    • Seed data (if needed): php artisan db:seed
    • Access the API at /api/posts (or your configured route).

First Use Case

Fetch filtered and paginated posts with relations:

curl "http://your-app.test/api/posts?q=title=laravel&with=author,comments&page=1&limit=5"
  • The ?q= shorthand filters by title=laravel.
  • ?with= loads author and comments relations.
  • Pagination is handled automatically.

Implementation Patterns

Core Workflow

  1. Controller Layer:

    • Extend Controller (auto-generated).
    • Delegate logic to the Service layer.
    • Use helper methods like sendSuccessResponse() for consistent API responses.
    public function index(): JsonResponse
    {
        $posts = $this->postService->getPostsCollection();
        return $this->successResponse('Posts retrieved', $posts);
    }
    
  2. Service Layer:

    • Orchestrate business logic.
    • Call handleApiQueryRequest() on the repository to leverage the query pipeline.
    public function getPostsCollection(): array
    {
        $data = $this->postRepository->getPostsData(['author']);
        return $this->prepareResourceResponse($data, PostResource::class);
    }
    
  3. Repository Layer:

    • Extend BaseRepository to use the Chain of Responsibility query pipeline.
    • Customize query behavior by overriding methods like applyFilters() or applySort().
    public function getPostsData(array $with = []): array
    {
        return $this->handleApiQueryRequest($this->query(), $with);
    }
    
  4. Query Pipeline Customization:

    • Extend or replace handlers in app/Core/Query/Handlers/ to modify behavior.
    • Example: Add a custom CacheHandler for query caching.
    // app/Core/Query/Handlers/Optimization/CacheHandler.php
    class CacheHandler extends AbstractQueryHandler
    {
        public function handle(Builder $builder, Request $request): Builder
        {
            $cacheKey = generateCacheKey($builder, $request);
            return Cache::remember($cacheKey, now()->addHours(1), fn() => $builder);
        }
    }
    

Integration Tips

  • Versioned APIs: Use nested namespaces for versioning:

    php artisan crudify:make V1/Posts/Post
    

    Routes will auto-generate under /api/v1/posts.

  • Custom Request Validation: Extend generated StoreRequest or UpdateRequest to add custom rules:

    public function rules(): array
    {
        return array_merge(parent::rules(), [
            'custom_field' => 'required|string|max:255',
        ]);
    }
    
  • Resource Customization: Override toArray() in the generated PostResource to shape responses:

    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'custom_field' => $this->whenLoaded('custom_field'),
        ];
    }
    
  • Soft Deletes: Enable soft deletes in the model:

    use Illuminate\Database\Eloquent\SoftDeletes;
    use HasUuids;
    
    class Post extends Model
    {
        use SoftDeletes, HasUuids;
        protected $dates = ['deleted_at'];
    }
    

    Use query params to control soft-deleted records:

    ?trashed=with   # Include soft-deleted
    ?trashed=only   # Only soft-deleted
    
  • Testing: Use the auto-generated feature test as a baseline:

    public function test_it_returns_a_paginated_list_of_posts()
    {
        $response = $this->getJson('/api/posts?limit=10');
        $response->assertStatus(200)
                 ->assertJsonStructure(['meta', 'data']);
    }
    

Gotchas and Tips

Pitfalls

  1. Query Pipeline Order:

    • Handlers execute in a strict order: SoftDelete → Relations → Filter → Sort → Pagination.
    • Overriding a handler (e.g., FilterHandler) requires understanding this sequence to avoid breaking expected behavior.
  2. Relation Loading Conflicts:

    • Explicit $with in handleApiQueryRequest() overrides model-level $with or Eloquent eager loads.
    • Debug with dd($this->query()->toSql()) to verify loaded relations.
  3. Soft Delete Quirks:

    • The ?trashed=with param includes soft-deleted records but does not restore them.
    • To restore, use Model::withTrashed()->find($id)->restore().
  4. Cache Invalidation:

    • The package does not auto-invalidate cache on model updates/deletes.
    • Manually clear cache or implement a CacheHandler with tag-based invalidation.
  5. Migration Conflicts:

    • Running crudify:make on an existing model overwrites the migration.
    • Backup or manually merge changes if the model evolves.

Debugging

  • Query Debugging: Log the final query before execution:

    $query = $this->query();
    \Log::info('Final Query:', ['sql' => $query->toSql(), 'bindings' => $query->getBindings()]);
    return $this->handleApiQueryRequest($query, $with);
    
  • Handler Debugging: Temporarily modify AbstractQueryHandler to log handler execution:

    public function handle(Builder $builder, Request $request): Builder
    {
        \Log::info(sprintf('Executing %s', static::class));
        return parent::handle($builder, $request);
    }
    
  • Validation Errors: Check the FormRequest for custom rules. Use:

    php artisan make:request CustomPostRequest
    

    Then extend the generated request to add rules.

Extension Points

  1. Custom Query Handlers: Add new handlers in app/Core/Query/Handlers/ and register them in BaseRepository:

    protected function getQueryHandlers(): array
    {
        return array_merge(parent::getQueryHandlers(), [
            new \App\Core\Query\Handlers\Custom\MyHandler(),
        ]);
    }
    
  2. Override Base Classes: Extend BaseRepository, BaseService, or Model in app/ to modify default behavior globally.

  3. Dynamic Route Binding: Customize route model binding in AppServiceProvider:

    Route::bind('post', function ($id) {
        return Post::withTrashed()->findOrFail($id);
    });
    
  4. API Schema Export: Re-generate OpenAPI schema after changes:

    php artisan crudify:make Post --export-api-schema
    
  5. Helper Utilities: Extend app/Helpers/Helpers.php to add custom helper functions:

    if (!function_exists('customHelper')) {
        function customHelper($input) {
            return strtoupper($input);
        }
    }
    

Configuration Quirks

  • Autoloading: After crudify:install, run composer dump-autoload if helpers are not recognized.

  • Namespace Conflicts: Avoid naming conflicts with Laravel’s core classes (e.g., UserController vs. AuthController).

  • Route Caching: Clear route cache after generating new CRUDs:

    php artisan route:clear
    
  • Testing: Use RefreshDatabase trait for tests to ensure a clean state:

    use RefreshDatabase;
    
    class PostTest extends TestCase
    {
        use RefreshDatabase;
        // ...
    }
    
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.
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge