PHPackages                             strides/laravel-api-module - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. strides/laravel-api-module

ActiveLibrary[API Development](/categories/api)

strides/laravel-api-module
==========================

A code generation toolkit for building clean, scalable Laravel APIs with modular architecture.

2.0.0(1w ago)015MITPHPPHP &gt;=8.1

Since Jan 6Pushed 1y ago1 watchersCompare

[ Source](https://github.com/Strides-hovo/Laravel-api-module)[ Packagist](https://packagist.org/packages/strides/laravel-api-module)[ RSS](/packages/strides-laravel-api-module/feed)WikiDiscussions master Synced yesterday

READMEChangelog (4)Dependencies (7)Versions (9)Used By (0)

Laravel API Module
==================

[](#laravel-api-module)

> A code generation toolkit for building clean, scalable Laravel APIs with modular architecture. Designed for teams that work exclusively with APIs and follow the **Action → Repository → Transformer** pattern.

[![Latest Stable Version](https://camo.githubusercontent.com/5ab632767e75287a51006385a5e9723747b3506703fbf896f4c965f8bb1aac5e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f737472696465732f6c61726176656c2d6170692d6d6f64756c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/strides/laravel-api-module)[![PHP Version](https://camo.githubusercontent.com/8c2ac16f3af88b9fbca15e8c495f832a7e5a1f8beced9bd00fe2ddad3a57485d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344253230382e312d626c75652e7376673f7374796c653d666c61742d737175617265)](https://www.php.net/)[![Laravel Version](https://camo.githubusercontent.com/b30919ef277aba212524b239ca7f2b302e0b525b0e0e478c6c03c2b276ea484d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d3925323025374325323031302532302537432532303131253230253743253230313225323025374325323031332d7265642e7376673f7374796c653d666c61742d737175617265)](https://laravel.com)[![License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE)[![Tests](https://camo.githubusercontent.com/7099d77b3a4250c870a473fa05dadf4cde89fd3a1ccf0c0b489d2311c2e55713/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d373225323070617373696e672d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](#testing)

---

Why This Package?
-----------------

[](#why-this-package)

When building APIs with Laravel, you end up creating the same set of files for every resource: model, migration, controller, request, repository, transformer, action, and so on. This package automates that with Artisan generators designed specifically for API development — no Blade views, no web routes, no frontend scaffolding.

```
php artisan module:make-model Product --all
```

One command. Model, migration, factory, seeder, controller, repository, transformer — all generated with correct namespacing, PSR-12 formatting, and placed in an isolated module directory.

---

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Module Management](#module-management)
- [Generators Reference](#generators-reference)
- [Architecture Pattern](#architecture-pattern)
- [Configuration](#configuration)
- [Migration Commands](#migration-commands)
- [Best Practices](#best-practices)
- [Testing](#testing)
- [Roadmap](#roadmap)
- [Contributing](#contributing)

---

Requirements
------------

[](#requirements)

DependencyVersionPHP`>= 8.1`Laravel`^9.0 | ^10.0 | ^11.0 | ^12.0 | ^13.0`ComposerLatest---

Installation
------------

[](#installation)

**1. Install via Composer**

```
composer require strides/laravel-api-module
```

**2. Publish configuration**

```
php artisan vendor:publish --provider="Strides\Module\Providers\ModuleServiceProvider"
```

**3. Register the Modules namespace in `composer.json`**

```
{
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Modules\\": "Modules/"
        }
    }
}
```

```
composer dump-autoload
```

**4. Add Modules test suite to `phpunit.xml`** *(optional but recommended)*

```

        Modules/*/Tests/*

```

---

Quick Start
-----------

[](#quick-start)

### Create a complete module

[](#create-a-complete-module)

```
php artisan module:make-module Product
```

This registers the module in `modules_name.json` and generates the full directory structure:

```
Modules/
└── Product/
    ├── Actions/
    ├── Broadcasting/
    ├── Casts/
    ├── Contracts/
    ├── Database/
    │   ├── Factories/
    │   ├── Migrations/
    │   └── Seeders/
    ├── Entities/
    ├── Events/
    ├── Helpers/
    ├── Http/
    │   ├── Controllers/
    │   ├── Middleware/
    │   ├── Requests/
    │   ├── Resources/
    │   └── Transformers/
    ├── Jobs/
    ├── Listeners/
    ├── Providers/
    ├── Repositories/
    ├── Services/
    └── Tests/

```

### Generate a model with all related files

[](#generate-a-model-with-all-related-files)

```
php artisan module:make-model Product Product --all
```

Generates: model, migration, factory, seeder, controller, repository.

### Generate specific components

[](#generate-specific-components)

```
php artisan module:make-model     Product Product --migration --controller --factory --seeder
php artisan module:make-controller Product ProductController --request --resource --repository
```

---

Module Management
-----------------

[](#module-management)

Every module is registered in `modules_name.json` at the project root. The package provides four commands to manage module lifecycle.

### List all modules

[](#list-all-modules)

```
php artisan module:list
```

```
+------------+-----------+--------------+----------------------------------+
| Module     | Status    | Path exists  | Path                             |
+------------+-----------+--------------+----------------------------------+
| Product    | Enabled   | ✓            | /var/www/Modules/Product         |
| Orders     | Disabled  | ✓            | /var/www/Modules/Orders          |
| Legacy     | Enabled   | ✗ Missing    | /var/www/Modules/Legacy          |
+------------+-----------+--------------+----------------------------------+

Total: 3  Enabled: 2  Disabled: 1  Missing: 1

```

### Enable / Disable a module

[](#enable--disable-a-module)

```
php artisan module:enable  Orders
php artisan module:disable Orders
```

Disabling a module prevents its service provider from loading — routes, migrations, and commands become inactive. Files are preserved.

### Clean up stale entries

[](#clean-up-stale-entries)

```
php artisan module:optimize
```

Scans `modules_name.json` and removes entries whose directories no longer exist. Asks for confirmation before writing.

```
The following modules have no directory and will be removed:
  - Legacy

Proceed? (yes/no) [yes]:
Done. Removed 1 stale entry from modules_name.json.

```

---

Generators Reference
--------------------

[](#generators-reference)

### Module

[](#module)

CommandDescription`module:make-module {name}`Create a complete module with full directory structure### Models &amp; Data

[](#models--data)

CommandFlagsDescription`module:make-model {module} {name}``-m` `-c` `-f` `-s` `-a`Eloquent model with optional related files`module:make-migration {module} {name}`Database migration`module:make-seeder {module} {name}`Database seeder`module:make-factory {module} {name}`Model factory`module:make-cast {module} {name}`Custom Eloquent attribute cast (`CastsAttributes`)**Model flags:**

FlagLongGenerates`-m``--migration`Migration`-c``--controller`Controller`-f``--factory`Factory`-s``--seeder`Seeder`-a``--all`All of the above### Controllers &amp; HTTP

[](#controllers--http)

CommandFlagsDescription`module:make-controller {module} {name}``-r` `-s` `-c` `-p` `-m` `-a`API controller`module:make-request {module} {name}`FormRequest validation class`module:make-transformer {module} {name}`Data transformer for API responses**Controller flags:**

FlagLongGenerates`-r``--request`FormRequest class`-s``--resource`API Resource class`-c``--collection`Resource Collection class`-p``--repository`Repository class`-m``--model`Model name for type hints`-a``--all`All of the above### Business Logic

[](#business-logic)

CommandDescription`module:make-action {module} {name}`Single-purpose invokable action class`module:make-service {module} {name}`Service class for complex operations`module:make-repository {module} {name}`Repository for data access abstraction### Events &amp; Async

[](#events--async)

CommandFlagsDescription`module:make-event {module} {name}``--listener[=Name]`Event class. Optionally creates a linked Listener`module:make-listener {module} {name}``--event=ClassName`Listener. `--event=` typehints the `handle()` parameter`module:make-job {module} {name}`Queueable job (`ShouldQueue` by default)**Event → Listener examples:**

```
# Create Event only
php artisan module:make-event Product ProductCreated

# Create Event + auto-generate a linked Listener
php artisan module:make-event Product ProductCreated --listener

# Create Event + Listener with a specific name
php artisan module:make-event Product ProductCreated --listener=SendProductNotification

# Create Listener with typed handle(ProductCreated $event)
php artisan module:make-listener Product SendProductNotification --event=ProductCreated
```

### Utilities

[](#utilities)

CommandDescription`module:make-interface {module} {name}`PHP interface (placed in `Contracts/`)`module:make-helper {module} {name}`Utility helper class`module:make-middleware {module} {name}`HTTP middleware`module:make-channel {module} {name}`Broadcasting channel with `join()` authorization`module:make-test {module} {name}`PHPUnit test class---

Architecture Pattern
--------------------

[](#architecture-pattern)

### Action → Repository → Transformer

[](#action--repository--transformer)

This package is built around a clean three-layer API architecture:

```
HTTP Request
    │
    ▼
FormRequest (validation)
    │
    ▼
Controller  ──────────────────────────────┐
    │                                      │
    ▼                                      │
Action (business logic)                   │
    │                                      │
    ▼                                      │
Repository (data access)                  │
    │                                      │
    ▼                                      │
Transformer (response format) ◄───────────┘
    │
    ▼
JSON Response

```

### Action

[](#action)

Actions are single-purpose invokable classes. One action, one responsibility.

```
// Modules/Product/Actions/CreateProductAction.php

namespace Modules\Product\Actions;

use Modules\Product\Entities\Product;
use Modules\Product\Repositories\ProductRepository;

class CreateProductAction
{
    public function __construct(private ProductRepository $repository) {}

    public function __invoke(array $data): Product
    {
        $product = $this->repository->create($data);
        event(new ProductCreated($product));
        return $product;
    }
}
```

### Repository

[](#repository)

Repositories abstract all database queries behind a clean interface.

```
// Modules/Product/Repositories/ProductRepository.php

namespace Modules\Product\Repositories;

use Illuminate\Support\Collection;
use Modules\Product\Entities\Product;

class ProductRepository
{
    public function all(): Collection
    {
        return Product::latest()->get();
    }

    public function find(int $id): Product
    {
        return Product::findOrFail($id);
    }

    public function create(array $data): Product
    {
        return Product::create($data);
    }

    public function update(Product $product, array $data): Product
    {
        $product->update($data);
        return $product->fresh();
    }

    public function delete(Product $product): bool
    {
        return $product->delete();
    }
}
```

### Transformer

[](#transformer)

Transformers define exactly what the API returns — nothing more, nothing less.

```
// Modules/Product/Http/Transformers/ProductTransformer.php

namespace Modules\Product\Http\Transformers;

use Illuminate\Support\Collection;
use Modules\Product\Entities\Product;

class ProductTransformer
{
    public function transform(Product $product): array
    {
        return [
            'id'          => $product->id,
            'name'        => $product->name,
            'slug'        => $product->slug,
            'price'       => (float) $product->price,
            'status'      => $product->status,
            'created_at'  => $product->created_at->toIso8601String(),
        ];
    }

    public function transformCollection(Collection $products): array
    {
        return $products->map(fn(Product $p) => $this->transform($p))->all();
    }
}
```

### Complete controller example

[](#complete-controller-example)

```
// Modules/Product/Http/Controllers/ProductController.php

namespace Modules\Product\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Routing\Controller;
use Modules\Product\Actions\CreateProductAction;
use Modules\Product\Actions\UpdateProductAction;
use Modules\Product\Actions\DeleteProductAction;
use Modules\Product\Http\Requests\StoreProductRequest;
use Modules\Product\Http\Transformers\ProductTransformer;
use Modules\Product\Repositories\ProductRepository;

class ProductController extends Controller
{
    public function __construct(
        private readonly CreateProductAction $create,
        private readonly UpdateProductAction $update,
        private readonly DeleteProductAction $delete,
        private readonly ProductRepository   $repository,
        private readonly ProductTransformer  $transformer,
    ) {}

    public function index(): JsonResponse
    {
        return response()->json([
            'data' => $this->transformer->transformCollection($this->repository->all()),
        ]);
    }

    public function store(StoreProductRequest $request): JsonResponse
    {
        $product = ($this->create)($request->validated());
        return response()->json(['data' => $this->transformer->transform($product)], 201);
    }

    public function show(int $id): JsonResponse
    {
        return response()->json(['data' => $this->transformer->transform($this->repository->find($id))]);
    }

    public function update(StoreProductRequest $request, int $id): JsonResponse
    {
        $product = ($this->update)($this->repository->find($id), $request->validated());
        return response()->json(['data' => $this->transformer->transform($product)]);
    }

    public function destroy(int $id): JsonResponse
    {
        ($this->delete)($this->repository->find($id));
        return response()->json(null, 204);
    }
}
```

---

Configuration
-------------

[](#configuration)

Publish and edit `config/module.php` to customize module structure:

```
return [
    'namespace'    => 'Modules',
    'modules'      => base_path('Modules'),
    'modules_name' => base_path('modules_name.json'),

    // Format generated .php files with laravel/pint (PSR-12) after creation.
    // Requires "laravel/pint" in require-dev. Silently skipped if not installed.
    'format_with_pint' => true,

    'paths' => [
        'modules' => base_path('Modules'),
        'generator' => [
            'model'                => ['path' => 'Entities',          'generate' => true],
            'migration'            => ['path' => 'Database/Migrations','generate' => true],
            'seeder'               => ['path' => 'Database/Seeders',   'generate' => true],
            'factory'              => ['path' => 'Database/Factories', 'generate' => true],
            'controller'           => ['path' => 'Http/Controllers',   'generate' => true],
            'request'              => ['path' => 'Http/Requests',      'generate' => true],
            'resource'             => ['path' => 'Http/Resources',     'generate' => true],
            'collection'           => ['path' => 'Http/Resources',     'generate' => true],
            'transformer'          => ['path' => 'Http/Transformers',  'generate' => true],
            'middleware'           => ['path' => 'Http/Middleware',     'generate' => true],
            'repository'           => ['path' => 'Repositories',       'generate' => true],
            'service'              => ['path' => 'Services',           'generate' => true],
            'action'               => ['path' => 'Actions',            'generate' => true],
            'event'                => ['path' => 'Events',             'generate' => true],
            'listener'             => ['path' => 'Listeners',          'generate' => true],
            'job'                  => ['path' => 'Jobs',               'generate' => true],
            'cast'                 => ['path' => 'Casts',              'generate' => true],
            'channel'              => ['path' => 'Broadcasting',       'generate' => true],
            'contract'             => ['path' => 'Contracts',          'generate' => true],
            'helper'               => ['path' => 'Helpers',            'generate' => true],
            'unit_test'            => ['path' => 'Tests/Unit',         'generate' => true],
            'route'                => ['path' => 'Routes',             'generate' => true],
            'route_service_provider' => ['path' => 'Providers',       'generate' => true],
            'service_provider'     => ['path' => 'Providers',         'generate' => true],
        ],
    ],
];
```

To disable a generator (for example if your team does not use Seeders):

```
'seeder' => ['path' => 'Database/Seeders', 'generate' => false],
```

---

Migration Commands
------------------

[](#migration-commands)

Migrations are scoped per module — you can run, rollback, or seed a single module without touching others.

```
# Run migrations for one module
php artisan module:migrate Product

# Run migrations for all modules
php artisan module:migrate

# Rollback (last 50 steps by default)
php artisan module:migrate-rollback Product

# Reset all module migrations
php artisan module:migrate-reset Product

# Refresh (rollback + re-run)
php artisan module:migrate-refresh Product

# Seed a module
php artisan module:migrate-seed Product

# Migration status
php artisan module:migrate-status Product
```

---

Best Practices
--------------

[](#best-practices)

**Keep actions single-purpose.** One action does one thing. `CreateProductAction`, `PublishProductAction`, `DeleteProductAction` — never `ProductAction`.

**Depend on interfaces, not implementations.** Bind your repository to an interface in the module's service provider so you can swap implementations in tests.

```
// In ProductServiceProvider::register()
$this->app->bind(ProductRepositoryInterface::class, ProductRepository::class);
```

**Fire events at the action level, not the controller.** Actions are the natural boundary for domain events.

```
public function __invoke(array $data): Product
{
    $product = $this->repository->create($data);
    event(new ProductCreated($product));  // ✅ here, not in the controller
    return $product;
}
```

**Let transformers control your API contract.** Never return `$model->toArray()` directly from a controller — transformers are your public API contract and protect against accidentally exposing model internals.

---

Testing
-------

[](#testing)

```
# Run the package's own test suite
composer test

# Run only a specific test class
vendor/bin/phpunit tests/Unit/ModelTest.php

# Run with code coverage
vendor/bin/phpunit --coverage-html coverage/
```

The package ships with **72 tests** covering all generators, module management commands, and the core builder infrastructure (including state isolation between multiple sequential builds).

When writing tests for your modules, actions and transformers are the highest-value targets:

```
// Modules/Product/Tests/Unit/Actions/CreateProductActionTest.php

namespace Modules\Product\Tests\Unit\Actions;

use Modules\Product\Actions\CreateProductAction;
use Modules\Product\Repositories\ProductRepository;
use Tests\TestCase;

class CreateProductActionTest extends TestCase
{
    public function test_creates_product_and_fires_event(): void
    {
        Event::fake([ProductCreated::class]);

        $repository = $this->mock(ProductRepository::class);
        $repository->shouldReceive('create')->once()->andReturn($this->product());

        $product = (new CreateProductAction($repository))(['name' => 'Widget']);

        $this->assertInstanceOf(Product::class, $product);
        Event::assertDispatched(ProductCreated::class);
    }
}
```

---

Roadmap
-------

[](#roadmap)

Features planned for future releases, in rough priority order.

### v1.1 — Developer experience

[](#v11--developer-experience)

- **`module:make-repository` as a standalone command** — currently only accessible as a `--repository` flag on `module:make-controller`. Will be available as a first-class generator.
- **`module:make-migration` with alter-table mode** — `php artisan module:make-migration Product add_status_to_products`. Stub and enum case are already in place; command pending.
- **PSR-4 verification on `module:enable`** — warn when enabling a module whose namespace is not in `composer.json` autoload.

### v1.2 — Inter-module communication

[](#v12--inter-module-communication)

- **`module:make-event` cross-module** — declare that a Listener in module `Orders` handles an Event from module `Product` without creating a tight dependency. Resolved through the service container.
- **Module dependency declaration** — optional `module.json` per module to declare `"requires": ["Product"]`, validated on `module:enable` and `module:optimize`.

### v1.3 — Advanced API patterns

[](#v13--advanced-api-patterns)

- **`module:make-policy`** — generate a Laravel Policy scoped to a module, with stubs for standard CRUD authorization.
- **`module:make-resource`** — standalone generator for `JsonResource` and `ResourceCollection` (currently accessible only as `--resource`/`--collection` flags on controller).
- **`module:make-dto`** — generate a typed Data Transfer Object class for passing validated data between layers without relying on raw arrays.
- **`module:make-enum`** — PHP 8.1 native enum, placed in `Enums/` inside the module.

### v1.4 — Tooling

[](#v14--tooling)

- **`module:make-contract` + auto-binding** — generate an interface and automatically add the `bind()` call to the module's service provider.
- **`module:publish-stubs`** — allow teams to override individual stub files without publishing the full package, similar to `php artisan stub:publish` in Laravel core.
- **GitHub Actions CI template** — `module:make-workflow` generates a `.github/workflows/ci.yml` configured for the project's PHP and Laravel version.

---

Troubleshooting
---------------

[](#troubleshooting)

**Migrations not found**Ensure the module is registered in `modules_name.json` (it happens automatically when you use `module:make-module` or any `module:make-*` command). If you created files manually, run `module:optimize` to sync the file.

**Classes not autoloading**Run `composer dump-autoload` after adding `"Modules\\": "Modules/"` to your `composer.json`.

**Service provider not loading**Verify that `modules_name.json` contains your module name with `true`. Use `php artisan module:list` to inspect the state.

**Queue jobs not processing**Jobs generated by `module:make-job` implement `ShouldQueue` by default. Ensure your queue driver is configured in `.env` (`QUEUE_CONNECTION=redis` or similar) and a worker is running.

---

Contributing
------------

[](#contributing)

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Write tests for new behaviour
4. Run the test suite: `composer test`
5. Ensure code is formatted: `composer pint`
6. Open a Pull Request

All contributions must include tests and pass PSR-12 formatting. Breaking changes require a discussion issue first.

---

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

---

Support
-------

[](#support)

- 🐛 **Bug reports:** [GitHub Issues](https://github.com/Strides-hovo/Laravel-api-module/issues)
- 💬 **Discussions:** [GitHub Discussions](https://github.com/Strides-hovo/Laravel-api-module/discussions)

---

*Inspired by [nWidart/laravel-modules](https://github.com/nWidart/laravel-modules). Built for teams that live in the API layer.*

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance65

Regular maintenance activity

Popularity6

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~225 days

Total

5

Last Release

11d ago

Major Versions

1.1.2 → 2.0.02026-06-23

### Community

Maintainers

![](https://www.gravatar.com/avatar/10c4116cd468cf6bebae6de734403f44ee7ad1f00eea675bf157fe84ffca9d3c?d=identicon)[Strides-hovo](/maintainers/Strides-hovo)

---

Top Contributors

[![Strides-hovo](https://avatars.githubusercontent.com/u/54514516?v=4)](https://github.com/Strides-hovo "Strides-hovo (17 commits)")

---

Tags

laravelmodulemodulesstrides

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/strides-laravel-api-module/health.svg)

```
[![Health](https://phpackages.com/badges/strides-laravel-api-module/health.svg)](https://phpackages.com/packages/strides-laravel-api-module)
```

###  Alternatives

[defstudio/telegraph

A laravel facade to interact with Telegram Bots

816333.8k3](/packages/defstudio-telegraph)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5021.9k](/packages/simplestats-io-laravel-client)[riclep/laravel-storyblok

A Laravel wrapper around the Storyblok API to provide a familiar experience for Laravel devs

6279.6k5](/packages/riclep-laravel-storyblok)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
