Search by

nameless / laravel-api-generator

Nameless0l

A professional Laravel API generator that automatically creates complete API structures with clean architecture, type safety, and best practices

Package info

github.com/Nameless0l/laravel-api-generator

pkg:composer/nameless/laravel-api-generator

Fund package maintenance!

Nameless0l

Buy Me A Coffee

Statistics

Installs: 113

Dependents: 0

Suggesters: 0

Stars: 22

Open Issues: 0

v4.0.0 2026-09-27 19:26 UTC

README

Latest Version on Packagist Total Downloads License

A professional Laravel package that generates complete, production-ready REST API structures from a single command. Built with clean architecture principles, PHP 8.1+ features, and Laravel best practices.

📖 Documentation: nameless0l.github.io/laravel-api-generator

Laravel API Generator 4.0 in two minutes: the MCP server for AI agents, the generated code and the VS Code extension

Demo

VS Code Extension

A visual interface is available: laravel-api-generator-vscode. Generate APIs, run migrations, tests, and browse documentation -- all from VS Code without touching the terminal.

v3.6 -- Models your IDE understands, native enums, Pest tests

  • Model PHPDoc -- every generated model ships a full @property docblock (fields, FK columns, relations, timestamps). Autocompletion works instantly in VS Code and PhpStorm, no ide-helper required.
  • Enum fields -- status:enum(draft,published) generates a backed PHP enum, the model cast, Rule::enum() validation and a faked factory value.
  • --pest -- generate Pest tests instead of PHPUnit.
  • Inverse relations everywhere -- declare one side in YAML/Mermaid, get both sides (and the FK migration) automatically.
  • Polymorphic relations -- morphTo / morphOne / morphMany in schema files and database introspection.
  • --add-fields -- evolve an existing entity day 30: incremental migration + in-place patches, manual code untouched.

v3.5 -- Generate from your database, a schema file, or a Mermaid diagram

  • --from-database -- point the generator at an existing (legacy) database and get a complete API for every table: fields, belongsTo/hasMany from foreign keys, belongsToMany from pivot tables, soft deletes from deleted_at.
  • api-schema.yaml -- describe your whole API in one declarative, versionable file and regenerate everything with php artisan make:fullapi.
  • --mermaid=diagram.mmd -- paste a Mermaid erDiagram or classDiagram (e.g. generated by an AI assistant) and turn it into a working API.
  • --query-builder -- generate index endpoints powered by spatie/laravel-query-builder (?filter[title]=...&sort=-created_at).

v3.4 -- Generate, seed, test, document, regenerate, introspect, customize

Swagger UI -- automatic interactive API documentation with Scramble:

Scramble Endpoints

Validation schemas -- your FormRequest rules become typed, documented constraints:

Scramble Schemas

Database seeding -- 10 records per entity, ready to use:

Seeded Database

Architecture

Every request flows through a clean, layered structure:

Generated architecture: HTTP request, FormRequest validation, thin controller, service layer with DTOs, model, database, resource serialization

What it generates

From a single command, the package creates 13 files per entity and registers the API route:

Layer File Location
Model Post.php app/Models/
Controller PostController.php app/Http/Controllers/
Service PostService.php app/Services/
DTO PostDTO.php app/DTO/
Requests StorePostRequest.php, UpdatePostRequest.php app/Http/Requests/
Resource PostResource.php app/Http/Resources/
Policy PostPolicy.php app/Policies/
Factory PostFactory.php database/factories/
Seeder PostSeeder.php database/seeders/
Migration *_create_posts_table.php database/migrations/
Feature Test PostControllerTest.php tests/Feature/
Unit Test PostServiceTest.php tests/Unit/
Route apiResource entry routes/api.php

Installation

composer require --dev nameless/laravel-api-generator

The service provider is auto-discovered. No additional configuration required.

Zero lock-in

The generator is a dev dependency: it never runs in production (composer install --no-dev leaves it out), and the generated code is plain Laravel with no dependency on this package (no base classes to extend, no runtime helpers). You can even remove the generator afterwards and everything keeps working.

Quick start

Single entity

php artisan make:fullapi Post --fields="title:string,content:text,published:boolean"

With soft deletes

php artisan make:fullapi Post --fields="title:string,content:text" --soft-deletes

This adds the SoftDeletes trait to the model, a softDeletes() column in the migration, and restore / forceDelete endpoints with their routes.

With Postman collection export

php artisan make:fullapi Post --fields="title:string,content:text" --postman

Generates a postman_collection.json at the project root, ready to import. Each entity gets a folder with List, Create, Show, Update, and Delete requests pre-configured with sample data.

With Sanctum authentication

php artisan make:fullapi Post --fields="title:string,content:text" --auth

This scaffolds a complete Sanctum-based auth system: AuthController (register, login, logout, user), LoginRequest, RegisterRequest, auth routes, and wraps your API resource routes inside auth:sanctum middleware.

Interactive wizard

php artisan make:fullapi --interactive

A step-by-step guided setup that lets you define the entity name, add fields one by one (with type, nullable, unique, and default value options), configure relationships, and preview everything before generation.

All options combined

php artisan make:fullapi Post --fields="title:string,content:text" --soft-deletes --postman --auth

Bulk generation from JSON

Create a class_data.json file at your project root (or download the sample Blog schema with Author, Category, Article, and Tag entities):

[
  {
    "name": "User",
    "attributes": [
      {"name": "name", "_type": "string"},
      {"name": "email", "_type": "string"}
    ],
    "oneToManyRelationships": [
      {"role": "posts", "comodel": "Post"}
    ]
  },
  {
    "name": "Post",
    "attributes": [
      {"name": "title", "_type": "string"},
      {"name": "content", "_type": "text"}
    ],
    "manyToOneRelationships": [
      {"role": "user", "comodel": "User"}
    ]
  }
]

Then run:

php artisan make:fullapi

Generate from an existing database (--from-database)

Working on a legacy project? Generate the complete API for every table in one command -- no schema to retype:

# Every user table (system tables and users are skipped automatically)
php artisan make:fullapi --from-database

# Only specific tables
php artisan make:fullapi --from-database --tables=products,orders

# Also create the migration files (useful to version a hand-built database)
php artisan make:fullapi --from-database --with-migrations

What the introspection detects:

  • Columns with their types and nullability, mapped to validation rules, casts, factories, and DTO types.
  • Foreign keys (real constraints, plus the <table>_id naming convention) become belongsTo relations, with the inverse hasMany on the parent model.
  • Pivot tables (two foreign keys, nothing else) become belongsToMany on both models instead of a useless PostTag entity.
  • deleted_at columns enable soft deletes (trait, restore/force-delete endpoints).

Migrations are not regenerated by default since the tables already exist. The users table is skipped so app/Models/User.php is never overwritten (pass --tables=users explicitly if you want it).

Declarative schema file (api-schema.yaml)

Describe the whole API in one file, commit it, and regenerate at will (full example):

options:
  query_builder: true        # optional, applies to every entity

entities:
  Category:
    fields:
      name: string unique
  Post:
    soft_deletes: true
    fields:
      title: string
      content: text nullable
      views: { type: integer, default: 0 }
    relations:
      category: belongsTo Category
      tags: belongsToMany Tag
  Tag:
    fields:
      name: string unique
php artisan make:fullapi --schema=api-schema.yaml

# Or just: if api-schema.yaml (or .yml / .json) exists at the project root,
# it is picked up automatically
php artisan make:fullapi

Fields accept a shorthand (string nullable unique default=x) or a mapping ({ type, nullable, unique, default, rules }). Relations use the Eloquent vocabulary: belongsTo, hasOne, hasMany, belongsToMany. Entities are generated parents-first so migrations run in foreign-key-safe order, and pivot migrations are created automatically for every belongsToMany.

Generate from a Mermaid diagram (--mermaid=)

Sketch your data model as a Mermaid diagram -- or ask your favorite AI to produce one -- and generate the API from it (full example):

erDiagram
    USER ||--o{ POST : writes
    POST }o--o{ TAG : tagged

    POST {
        string title
        text content
        datetime deleted_at
    }
    TAG {
        string name UK
    }
Loading
php artisan make:fullapi --mermaid=blog.mmd

Both erDiagram and classDiagram are supported: cardinalities (||--o{, "1" --> "*") become the right Eloquent relations on both sides, compositions/aggregations (*--, o--) become hasMany, UK markers become unique fields, deleted_at enables soft deletes, and markdown fences/comments are stripped so you can paste diagrams as-is.

Generate from an OpenAPI spec (--openapi=)

Got an OpenAPI 3.0, 3.1 or Swagger 2.0 document, in JSON or YAML? Each object schema becomes an entity (full example):

php artisan make:fullapi --openapi=openapi.yaml --dry-run
php artisan make:fullapi --openapi=openapi.yaml

References become belongsTo, lists of references hasMany (or belongsToMany when both sides list each other), postId next to a Post schema a relation, string enums PHP enums, deletedAt soft deletes, and optional properties nullable columns. Error, pagination and payload schemas such as NewPet or CreatePetRequest are skipped, each with a warning. See OpenAPI Specs.

Spatie QueryBuilder integration (--query-builder)

Generate index endpoints backed by the community-standard spatie/laravel-query-builder:

composer require spatie/laravel-query-builder
php artisan make:fullapi Post --fields="title:string,content:text" --query-builder

The generated service keeps the parameters of the built-in index (see Pagination, filters and sorting) and hands them to Spatie, with exact filters:

GET /api/posts?filter[title]=laravel&sort=-created_at&per_page=20

Spatie answers 400 for an unknown filter or sort. For partial matches, swap AllowedFilter::exact for AllowedFilter::partial in the service.

The flag works with every generation mode (--from-database, --schema, --mermaid, interactive), and query_builder: true can also be set globally or per entity in the schema file.

Native enum fields

php artisan make:fullapi Article --fields="title:string,status:enum(draft,published,archived)"

One field definition produces the whole chain:

  • app/Enums/ArticleStatus.php -- a backed enum ArticleStatus: string with a case per value, named after the entity and the field
  • Model -- 'status' => ArticleStatus::class in casts() and @property ArticleStatus $status in the PHPDoc
  • Request -- Rule::enum(ArticleStatus::class) validation
  • Factory -- fake()->randomElement(ArticleStatus::cases())
  • Migration -- $table->enum('status', ['draft', 'published', 'archived'])

In a schema file: status: enum(draft,published) default=draft.

Pest tests (--pest)

php artisan make:fullapi Post --fields="title:string" --pest

Generates it(...) / expect(...) style tests instead of PHPUnit classes -- the same coverage (CRUD endpoints, validation, service layer), in the style new Laravel projects use by default. Also available as pest: true in the schema file's global or per-entity options.

Evolve an existing entity (--add-fields)

Generators are great on day 1 and useless on day 30, because regenerating wipes your manual changes. --add-fields patches instead of regenerating:

php artisan make:fullapi Post --add-fields="excerpt:text,status:enum(draft,published)"
php artisan migrate
  • Creates an incremental Schema::table() migration (with down())
  • Appends to the fillable columns, the casts and the PHPDoc block of the existing model
  • Inserts the validation rules, factory values and resource fields in place
  • Generates the enum class when needed
  • Skips fields that already exist; never touches your custom methods

The DTO (constructor promotion) and the generated tests are left alone and reported as manual follow-ups.

Delete generated API

# Delete a specific entity
php artisan delete:fullapi Post

# Delete all entities defined in class_data.json
php artisan delete:fullapi

The delete command also unregisters the seeder from DatabaseSeeder.php and removes the API route, so your codebase stays clean.

Regenerate selected files (--only=)

Modified your migration and want a fresh Resource or Test without retyping everything? Use --only=Type[,Type] to run only specific generators:

# Regenerate only the feature & unit tests
php artisan make:fullapi Post --fields="title:string,content:text" --only=FeatureTest,UnitTest

# Regenerate just the Resource
php artisan make:fullapi Post --fields="title:string,content:text" --only=Resource

When --only= is set, the migration, the apiResource route and the DatabaseSeeder registration are left untouched -- only the listed artifacts are rewritten.

Available types: Model, Controller, Service, DTO, Request, Resource, Migration, Factory, Seeder, Policy, FeatureTest, UnitTest.

Introspect an existing database

The api-generator:introspect command emits the project's database schema as JSON, so any tooling can scaffold APIs on top of legacy databases without retyping the schema:

# List all user tables (system tables like migrations / sessions / personal_access_tokens are filtered out)
php artisan api-generator:introspect

# Describe one table (column names, normalized types, soft_deletes flag)
php artisan api-generator:introspect --table=products

This powers the Import from Database feature in the VS Code extension. To generate the APIs directly instead of just inspecting the schema, use make:fullapi --from-database (see above).

Validate customized stubs

If you customize stubs (see below), api-generator:validate-stubs checks that every required {{placeholder}} is still present so generation cannot silently produce broken code:

php artisan api-generator:validate-stubs
php artisan api-generator:validate-stubs --json   # machine-readable, exit code 1 on error

Wire this into your CI to catch broken stubs before they reach production.

Let coding agents generate the API (MCP)

Install laravel/mcp (Laravel 12.41+) and register the server in your agent. With Claude Code:

composer require --dev laravel/mcp
claude mcp add -s project laravel-api-generator -- php artisan api-generator:mcp

The agent gets four tools, list-entities, plan-api, generate-api and add-fields. It previews before writing and never overwrites a file you edited by hand. The VS Code extension registers the server for Copilot on its own. See MCP Server for Cursor, Docker and Sail.

Customize the generated code (stubs)

Publish the package's stubs to your project so you can edit the templates the generators inject into:

php artisan vendor:publish --tag=api-generator-stubs

This copies every .stub into stubs/vendor/laravel-api-generator/. The StubLoader always checks this folder first and falls back to the package's defaults, so you can override only the stubs you need.

After editing, run api-generator:validate-stubs (or let the VS Code extension run it automatically before each generation) to verify your customizations.

Command reference

php artisan make:fullapi {name?} {--fields=} {--soft-deletes} {--postman} {--auth} {--interactive} {--only=}
                         {--schema=} {--mermaid=} {--openapi=} {--from-database} {--tables=} {--with-migrations} {--query-builder}
                         {--pest} {--json-api} {--add-fields=} {--dry-run} {--json} {--force}
php artisan delete:fullapi {name?} {--force} {--dry-run}
php artisan api-generator:clean-routes {--dry-run}
php artisan api-generator:introspect {--table=}
php artisan api-generator:validate-stubs {--json}
php artisan api-generator:install
php artisan api-generator:serve {--stdio}
php artisan api-generator:mcp
Argument / Option Description
name Entity name (PascalCase). Omit to use the schema file / JSON mode.
--fields Field definitions in name:type format, comma-separated.
--soft-deletes Add SoftDeletes trait, migration column, restore/forceDelete endpoints.
--postman Export a Postman v2.1 collection after generation.
--auth Scaffold Sanctum authentication (AuthController, requests, routes, middleware).
--interactive Launch the step-by-step wizard for guided entity creation.
--only=Type,Type Regenerate only the listed artifacts; skip route + seeder registration.
--schema=file Generate every entity from a declarative YAML/JSON schema file. --schema=- reads the schema from stdin.
--mermaid=file Generate every entity from a Mermaid erDiagram / classDiagram.
--openapi=file Generate an entity from each object schema of an OpenAPI 3 or Swagger 2 document, JSON or YAML. --openapi=- reads it from stdin.
--from-database Introspect the existing database and generate APIs for its tables.
--tables=a,b Restrict --from-database to specific tables.
--with-migrations With --from-database: also generate the migration files.
--query-builder Use spatie/laravel-query-builder for index filtering and sorting.
--pest Generate Pest tests instead of PHPUnit.
--json-api Generate JSON:API-compliant resources (JsonApiResource, Laravel 12.45+). Falls back to a standard resource on older versions.
--add-fields=a:type,b:type Add fields to an existing entity: incremental migration + in-place patches.
--dry-run Run the whole generation and list the files it would create or update, without writing anything.
--json Print one JSON document instead of the text report, for scripts, editors and agents. Not available with --interactive. See Tools & Agents.
--force Overwrite the files you edited by hand since they were generated. Without it they are kept and reported.

Supported field types

Type Database column PHP type Validation rule
string VARCHAR(255) string string|max:255
text TEXT string string
integer / int INTEGER int integer
bigint BIGINTEGER int integer
boolean / bool BOOLEAN bool boolean
float / decimal DECIMAL(8,2) float numeric
json JSON array json
date DATE DateTimeInterface date
time TIME string date_format:H:i,H:i:s
datetime DATETIME DateTimeInterface date
timestamp TIMESTAMP DateTimeInterface date
uuid UUID string uuid
enum(a,b,...) ENUM('a','b') App\Enums\FieldName (backed enum + cast) Rule::enum()

Append :primary (CLI) or the primary modifier (schema file) to make a field the primary key instead of the default id -- the model, migration and every incoming relation (FK name, column type, references(), exists rule) follow automatically:

php artisan make:fullapi Country --fields="code:string:primary,name:string"

Relationship types

Supported in JSON mode via class_data.json:

JSON key Eloquent method Foreign key
oneToOneRelationships hasOne() On related table
oneToManyRelationships hasMany() On related table
manyToOneRelationships belongsTo() On current table
manyToManyRelationships belongsToMany() Pivot table

Model inheritance is also supported via the "parent" key in JSON definitions.

Schema files (--schema=) additionally support polymorphic relations:

entities:
  Post:
    fields:
      title: string
    relations:
      comments: morphMany Comment
  Comment:
    fields:
      body: text
    relations:
      commentable: morphTo

morphTo emits $table->morphs('commentable') in the migration and morphTo() on the model; morphOne / morphMany point back with the right morph name. In schema files, Mermaid diagrams and class_data.json, declaring one side of a belongsTo / hasOne / hasMany / belongsToMany is enough: the inverse and its FK column are synthesized automatically, exactly like --from-database does.

Generated code examples

Controller

The generated controller receives the model through route model binding, asks the policy before every action, and delegates to the service layer through a DTO. The index endpoint is paginated, filterable and sortable out of the box.

class PostController extends Controller
{
    public function __construct(
        private readonly PostService $service
    ) {}

    public function index(Request $request)
    {
        Gate::authorize('viewAny', Post::class);

        $posts = $this->service->getAll($request->query());
        return PostResource::collection($posts);
    }

    public function store(StorePostRequest $request)
    {
        Gate::authorize('create', Post::class);

        $dto = PostDTO::fromRequest($request);
        $post = $this->service->create($dto);
        return new PostResource($post);
    }

    public function show(Post $post)
    {
        Gate::authorize('view', $post);

        return new PostResource($post);
    }

    public function update(UpdatePostRequest $request, Post $post)
    {
        Gate::authorize('update', $post);

        $dto = PostDTO::fromRequest($request);
        return new PostResource($this->service->update($post, $dto));
    }

    public function destroy(Post $post)
    {
        Gate::authorize('delete', $post);

        $this->service->delete($post);
        return response()->noContent();
    }
}

Service

The service layer handles business logic and pages, filters and sorts the index. It saves what the DTO carries, so an update only touches the fields the request sent. With --soft-deletes, it also includes restore() and forceDelete() methods.

class PostService
{
    private const FILTERS = ['id', 'title', 'content', 'published'];

    private const SORTS = ['id', 'title', 'content', 'published', 'created_at', 'updated_at'];

    public function paginate(array $query = []): LengthAwarePaginator
    {
        // filter[field]=value on FILTERS, sort=field,-field on SORTS (default -id),
        // per_page capped at 100, then ->paginate(...)->withQueryString()
    }

    public function create(PostDTO $dto): Post
    {
        return Post::create($dto->toArray());
    }

    public function update(Post $post, PostDTO $dto): Post
    {
        $post->update($dto->toArray());
        return $post->fresh();
    }

    public function delete(Post $post): bool
    {
        return $post->delete();
    }
}

Requests

StorePostRequest holds the creation rules. UpdatePostRequest prefixes each of them with sometimes, so a PATCH may send a single field, and its unique rules ignore the post being updated:

public function rules(): array
{
    return [
        'title' => 'sometimes|required|string|max:255',
        'slug' => ['sometimes', 'required', 'string', 'max:255', Rule::unique('posts')->ignore($this->route('post'))],
        'published_at' => 'sometimes|nullable|date',
    ];
}

DTO

Readonly data transfer objects built from the validated data. toArray() returns the fields the request sent, which keeps a partial update partial:

readonly class PostDTO
{
    public function __construct(
        public ?string $title = null,
        public ?string $content = null,
        public ?bool $published = null,
        private ?array $provided = null
    ) {}

    public static function fromRequest(StorePostRequest|UpdatePostRequest $request): self
    {
        $data = $request->validated();

        return new self(
            title: $data['title'] ?? null,
            content: $data['content'] ?? null,
            published: isset($data['published']) ? (bool) $data['published'] : null,
            provided: array_keys($data)
        );
    }

    public function toArray(): array
    {
        $values = get_object_vars($this);
        unset($values['provided']);

        return $this->provided === null ? $values : array_intersect_key($values, array_flip($this->provided));
    }
}

Policy

Every controller action goes through the entity's policy. The generated policy accepts guests and returns true, so the API is public until you restrict it:

public function update(?User $user, Post $post): bool
{
    return $user?->id === $post->user_id;
}

Feature test

Automatically generated PHPUnit tests covering all CRUD endpoints:

class PostControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_can_list_posts(): void
    {
        Post::factory()->count(3)->create();
        $response = $this->getJson('/api/posts');
        $response->assertStatus(200)->assertJsonCount(3, 'data');
    }

    public function test_can_create_post(): void
    {
        $data = ['title' => 'test_title', 'content' => 'Test text content'];
        $response = $this->postJson('/api/posts', $data);
        $response->assertStatus(201);
        $this->assertDatabaseHas('posts', $data);
    }

    public function test_can_patch_post(): void
    {
        $post = Post::factory()->create()->fresh();
        $response = $this->patchJson("/api/posts/{$post->getKey()}", ['title' => 'test_title']);
        $response->assertStatus(200);
        $this->assertSame(
            Arr::except($post->getAttributes(), ['title', 'updated_at']),
            Arr::except($post->fresh()->getAttributes(), ['title', 'updated_at'])
        );
    }

    // ... show, update, delete, validation tests
}

Pagination, filters and sorting

Every generated index endpoint is paginated, filterable and sortable, without any extra package:

GET /api/posts?filter[published]=1&sort=-created_at,title&page=2&per_page=20

The response carries data, links and meta. Filters match exact values on the primary key and the fillable columns (JSON columns excluded). sort takes a comma-separated list where a leading - means descending, and the default order is the primary key, newest first. Unknown filters and sorts are ignored. per_page defaults to 15 and stops at 100. To change these values, publish the config before generating, since they are written into each generated service:

php artisan vendor:publish --tag=api-generator-config

Soft deletes

When using --soft-deletes, the generator adds:

  • SoftDeletes trait and import to the model
  • $table->softDeletes() to the migration
  • restore() and forceDelete() methods to the controller and service
  • Two additional routes, which also find a soft deleted post:
POST   /api/posts/{post}/restore
DELETE /api/posts/{post}/force-delete

Postman collection

The --postman flag generates a postman_collection.json file at the project root. The collection follows the Postman v2.1 schema and includes:

  • A folder per entity
  • Pre-configured requests for List, Create, Show, Update, and Delete
  • Sample request bodies with appropriate field values
  • A base_url variable (defaults to http://localhost:8000/api)

Import the file directly into Postman to start testing immediately.

Sanctum authentication

The --auth flag scaffolds a complete token-based authentication system using Laravel Sanctum:

Generated files:

  • app/Http/Controllers/AuthController.php -- register, login, logout, user endpoints
  • app/Http/Requests/LoginRequest.php -- email + password validation
  • app/Http/Requests/RegisterRequest.php -- name, email, password + confirmation validation

Generated routes:

// Public, limited to 6 requests per minute
POST /api/register
POST /api/login

// Protected (auth:sanctum)
POST /api/logout
GET  /api/user

// Your API resources are also wrapped in auth:sanctum
GET  /api/posts          (requires token)
POST /api/posts          (requires token)
// ...

After running with --auth, install Sanctum if not already present:

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

Add the HasApiTokens trait to your User model, and your API is secured.

Interactive mode

The --interactive flag launches a step-by-step wizard that guides you through entity creation:

  1. Entity name -- enter the model name in PascalCase
  2. Fields -- add fields one by one, choosing type, nullable, unique, and default value for each
  3. Relationships -- optionally add belongsTo, hasMany, hasOne, or belongsToMany relations
  4. Options -- enable soft deletes, Sanctum auth, Postman export
  5. Preview -- review the full entity definition and file list before confirming
  6. Generate -- confirm and generate all files

This mode is ideal for developers who prefer a guided experience or want to configure field constraints (unique, defaults) that aren't available in the --fields string syntax.

Extending the generator

Create a custom generator by extending AbstractGenerator:

use nameless\CodeGenerator\EntitiesGenerator\AbstractGenerator;
use nameless\CodeGenerator\ValueObjects\EntityDefinition;

class CustomGenerator extends AbstractGenerator
{
    public function getType(): string
    {
        return 'Custom';
    }

    public function getOutputPath(EntityDefinition $definition): string
    {
        return app_path("Custom/{$definition->name}Custom.php");
    }

    protected function getStubName(): string
    {
        return 'custom'; // loads stubs/custom.stub
    }

    protected function getReplacements(EntityDefinition $definition): array
    {
        return ['modelName' => $definition->name];
    }

    protected function generateContent(EntityDefinition $definition): string
    {
        return $this->processStub($definition);
    }
}

Register it in your service provider and it will be called automatically during generation.

API documentation with Scramble

The package integrates seamlessly with Scramble to provide automatic, interactive API documentation -- no annotations or manual setup required.

Scramble API Docs

Setup

composer require dedoc/scramble --dev
php artisan serve

Then open http://localhost:8000/docs/api in your browser.

What you get

Scramble automatically analyzes your generated controllers, requests, and resources to produce a full OpenAPI 3.x specification with:

  • Interactive Swagger UI -- test endpoints directly from the browser with "Send API Request"
  • Auto-detected schemas -- ProductRequest, ProductResource, etc. are inferred from your FormRequest rules and API Resource structure
  • Validation rules as constraints -- required|string|max:255 becomes a required string field with <= 255 characters in the docs
  • Request/response examples -- sample JSON bodies are generated automatically
  • Grouped endpoints -- each entity (Product, Post, etc.) gets its own section with all CRUD operations

Scramble Schemas

Endpoints

URL Description
/docs/api Interactive Swagger UI
/docs/api.json Raw OpenAPI 3.x JSON specification

Note: Scramble is a dev dependency. It won't affect your production deployment.

Database seeding

Generated seeders are automatically registered in DatabaseSeeder.php. After generating your API and running migrations:

php artisan migrate:fresh --seed

Each entity seeder creates 10 records using the generated factory. The delete:fullapi command also cleans up the seeder registration.

Seeded Database

Development

# Install dependencies
composer install

# Run tests
composer test

# Static analysis
composer analyse

# Code formatting
composer format

Local testing in a Laravel project

Add the package as a path repository in your Laravel project's composer.json:

{
    "repositories": [
        {
            "type": "path",
            "url": "../laravel-api-generator",
            "options": {"symlink": true}
        }
    ],
    "require": {
        "nameless/laravel-api-generator": "@dev"
    }
}

Then run composer update.

Requirements

  • PHP >= 8.2
  • Laravel 12.x or 13.x (Laravel 10 and 11 projects stay on ^3.15)
  • Optional: laravel/mcp for the MCP server (Laravel 12.41+)

Contributing

Contributions are welcome. Please see CONTRIBUTING.md for details.

Support the project

This package is free and MIT-licensed, and will stay that way. If it saves you time, you can support its development through GitHub Sponsors or Buy Me a Coffee.

Security

If you discover a security vulnerability, please email loicaronmbassiewolo@gmail.com instead of using the issue tracker.

Credits

Changelog

See CHANGELOG.md for the full version history.

License

MIT. See LICENSE for details.