mitulgolakiya/laravel-api-generator
Laravel API Generator scaffolds complete RESTful APIs from your database tables: controllers, models, routes, requests, resources, and docs, with pagination, filtering, sorting, and relationship support built in.
Know what you're installing first. This package is archived (last release May 2015) and targets the Laravel 5.0–5.3 era: service-provider registration in config/app.php, app/Http/routes.php-style routing, and controllers that call $this->middleware(...) in the constructor. It will not boot cleanly on Laravel 8+ without work. The realistic entry points are:
Minimal steps (legacy app):
# 1. Clean git tree — you want to diff everything it touches
git checkout -b api-generator-scaffold
# 2. Install as a dev dependency only
composer require --dev mitulgolakiya/laravel-api-generator
# 3. Register the provider in config/app.php 'providers'
Mitul\Generator\GeneratorServiceProvider::class,
# 4. Publish config and inspect it before running anything
php artisan vendor:publish
Where to look first, in this order:
php artisan list | grep -i api — confirm the actual command name and flags for your installed version before trusting any README. Then php artisan api:generate --help.config/generator.php (whatever the publish tag drops) — this is where output paths, base namespaces, model/controller namespaces, and stub locations live. Read it fully; half the "wrong output location" complaints are just this file.src/ stubs directory — this is the real source of truth for what the generated code looks like in your version.First use case: pick one small, well-normalized table with at least one real foreign key (e.g. products with category_id). Run the interactive command against it, then immediately git diff:
php artisan api:generate # interactive: table, model, controller, routes
git status && git diff
Commit the raw, untouched generated output as its own commit before you edit a line. That commit is your reference for every later regeneration and merge.
Schema-first, then generate. The generator reads information_schema — your database is the spec. Before running it, audit the table:
FOREIGN KEY constraints (not just _id columns) — relationship inference depends on them.NULL / NOT NULL on every column — this drives required vs sometimes/nullable in the form requests.varchar lengths, enum/set definitions, decimal(p,s) — these become max:, in:, and numeric rules.deleted_at timestamp if you want soft-delete detection, and standard created_at/updated_at if you want timestamps inferred.If your schema is sloppy, you will spend longer fixing generated validation than writing the files by hand.
One table, one commit. The generator is interactive and table-at-a-time. Resist batching everything into one run — a single bad table makes the whole diff unreviewable.
php artisan api:generate # products
git add -A && git commit -m "scaffold: products (generated, untouched)"
# tweak, then:
git commit -am "products: auth, eager loads, tightened validation"
Never regenerate over customized files. There is no safe merge or rollback. If a table's schema changes materially, generate into a scratch branch, diff against your hardened version, and hand-port the deltas. Treat the generator as a one-shot bootstrapper, not a codegen pipeline.
Harden immediately after generating. Generated controllers are scaffolding, not production code. The standard follow-up pass:
Route::middleware('auth:api')->group(...).php artisan make:policy) and swap Model::findOrFail() for $this->authorize(...) calls.Route::resource to Route::apiResource (Laravel 5.5+) to drop create/edit routes that make no sense for an API.with([...]) eager loads in index/show — the generated index paginates but typically doesn't eager-load, so relationships N+1 immediately.JsonResource/ResourceCollection if you're on 5.5+, replacing the raw response()->json() calls.Porting into a modern app. Generate in the throwaway 5.x skeleton against a database dump, then copy files across and fix the known drift points:
| Generated (5.x) | Modern equivalent |
|---|---|
app/Http/routes.php |
routes/api.php |
$this->middleware('auth') in constructor |
Route::middleware() in route file |
Route::resource |
Route::apiResource |
response()->json($model) |
new ModelResource($model) |
App\User namespace hardcodes |
your configured namespaces |
Integration tip — generate before you write migrations for legacy schemas. The highest-value scenario is a database you inherited but didn't design: dump it, restore to a dev DB, point the generator at it, and get models with accurate $fillable, casts, and relationships in minutes. Then write migrations from the generated models if you need them.
Extend via stubs, not via post-processing scripts. If you find yourself applying the same five edits to every generated controller, publish/fork the stubs into your app and edit those. That's the only sustainable customization point this package offers.
It's abandoned — pin and isolate. Do not put this in require for production. require-dev, generate, commit, then composer remove --dev so future composer update runs can't resurrect it or pin you to an old framework.
Relationship inference is FK-only. No FK constraint = no belongsTo/hasMany. MyISAM tables, or columns named category_id without the constraint, silently produce a model with zero relationships and you'll blame the generator.
Validation is type-derived, not business-derived. Expect required|max:255 on a varchar(255) that actually accepts a comma-separated list, in: rules missing for enum-like columns stored as varchar, and unique: rules that ignore soft deletes. Always add Rule::unique(...)->ignore($id) manually and re-check sometimes vs required on PATCH-style updates.
Table prefixes and non-public Postgres schemas break things. If you use DB_PREFIX, generated unique: rules and FK lookups can reference unprefixed names. For Postgres, confirm the connection's search_path includes the schema holding your tables — the generator queries information_schema scoped to the current connection.
Reserved words and irregular plurals. A table named order or status produces a model whose class name collides with SQL keywords or Laravel internals; people/data-style irregular names get the wrong controller and route names. Rename in the interactive prompt rather than fixing ten files afterward.
Soft deletes and timestamps are heuristic. Detection is based on the presence of deleted_at / created_at. Custom timestamp column names or a boolean is_deleted flag won't be picked up — add SoftDeletes and $dates by hand.
The generated index is a pagination footgun. ?per_page=100000 will happily serialize your whole table. Add a clamp in the controller or a global per_page cap:
$perPage = min((int) $request->input('per_page', 15), 100);
Auth is wide open by default. Every generated route is publicly reachable. If you scaffold ten tables and deploy without wrapping them in auth:api, you've shipped ten open CRUD endpoints. Make the middleware group part of the same commit as the generated code.
No dry-run, no rollback, silent overwrite. The command writes files immediately and will clobber existing ones without confirmation in most versions. Always start from a clean git tree and commit before each run. If the output looks wrong, git checkout . is your undo.
Debugging a failed run: re-run with -v / -vvv, and check that (a) the table name matches exactly (it is case-sensitive on Linux/Postgres), (b) the DB user can read information_schema, and (c) the target directories in config/generator.php exist and are writable. Most failures are permissions or a namespace that doesn't map to a real PSR-4 root.
Extension points, ranked by usefulness: published config (paths, namespaces, base controller) → stubs (code shape) → a BaseApiController you point the config at, so cross-cutting concerns like pagination clamping and response formatting live in one place instead of in every generated file.
How can I help you explore Laravel packages today?