phfoxer/apigenerate
phfoxer/apigenerate scaffolds RESTful API endpoints for Laravel apps, generating controllers, routes, requests, resources, and docs from your models so you can ship consistent, ready-to-use APIs with far less boilerplate code.
Before you install, check compatibility. Last release was March 2023 and the package lists no dependents, so confirm the illuminate/* constraints in its composer.json against your Laravel version before committing to it. On Laravel 11/12 you may need --with-all-dependencies or a fork.
composer require phfoxer/apigenerate --dev
php artisan list | grep -i api # confirm the exact command name
Auto-discovery should register the service provider (standard for Laravel 5.5+ packages). If commands don't appear, check config/app.php providers and run php artisan vendor:publish --provider="Phfoxer\ApiGenerate\..." to surface config and stubs.
Where to look first, in order:
--force, resource/request flags) are the whole contract of this package.src/Console/Commands/ (or equivalent) — tells you exactly which files get written, to which paths, and which stubs are used.stubs/ — the generated code you'll actually live with day to day; read it before generating 20 files.config/ — namespace, path, and route-file settings.First use case: scaffold a single CRUD endpoint end to end and inspect the diff.
php artisan <generate-command> Post # or --model=Post, per README
git status && git diff --stat
Generate one resource, read every produced file, then decide whether the output matches your team's conventions. Do this before batch-generating.
Treat it as a scaffolder, not a runtime dependency. The package's value is the first 80% of boilerplate — controller, routes, request, resource, maybe a model/migration. Nothing should reference the package at runtime, so it belongs in require-dev if it only ships commands.
Scaffold-then-refine, and commit the generated output. Because the package is stale, generated code should be treated as your code from the moment it lands. Once generated, edit freely — don't expect to re-run the generator over customized files later.
Wrap it in a project-local command. If your team needs consistent output (base controller, authorize() calls, pagination defaults, ApiResource instead of raw JSON), publish the stubs and override them, then add your own thin command:
// app/Console/Commands/MakeApi.php
protected $signature = 'make:api {model}';
public function handle() {
$this->call('<generate-command>', ['name' => $this->argument('model')]);
// post-process: register routes, inject traits, run Pint
}
This insulates you from the package disappearing or breaking on the next Laravel major.
Pair the output with conventions you already have. Typical follow-ups after generation:
Request classes into App\Http\Requests\Api\... and add real rules.JsonResource / ResourceCollection.routes/api.php under a versioned prefix (/api/v1/...) if the generator writes a flat file.Route::apiResource(...) explicitly rather than relying on generated route files, so route caching behavior is predictable.Batch/domain workflow. For modular apps, generate per-domain in a loop and immediately run pint plus your static analyser:
for m in Post Comment Tag; do php artisan make:api $m; done
vendor/bin/pint app/Http && vendor/bin/phpstan analyse
Catching namespace or import drift here is far cheaper than after 30 files.
CI integration. Useful as a one-shot developer tool, not a pipeline step. If you do run it in CI to detect drift, generate into a temp directory and diff — never overwrite committed source.
Str::random over Str::password, docblock-heavy controllers, older validation syntax). Diff output against a fresh php artisan make:controller --api on your Laravel version to spot drift.--force. Run it in a clean working tree and git diff after every invocation; there's no undo.App\Http\Controllers\Api). If you use a custom root namespace or DDD layout, expect to publish and edit stubs rather than rely on config.routes/api.php, remember that php artisan route:cache must be re-run and that a fatal in a generated route file fails silently-ish at cache time. Debug with php artisan route:list after generation.php artisan list showing nothing means the provider didn't register — check composer's extra.laravel.providers, run composer dump-autoload, and clear bootstrap/cache/packages.php.-vvv and check the exit code; a batch loop that "succeeds" may have written nothing.packages/ (Composer path repository) is a legitimate and often the right move if it becomes load-bearing.require-dev.How can I help you explore Laravel packages today?