spatie/laravel-openapi-cli
Generate Laravel Artisan commands from an OpenAPI spec. Each API endpoint becomes its own command with typed options for params and request bodies, plus auth, base URL, caching, redirects, and output formatting—ideal for building API CLIs with Laravel Zero.
Install the Package:
composer require spatie/laravel-openapi-cli
Publish the config (if needed):
php artisan vendor:publish --provider="Spatie\OpenApiCli\OpenApiCliServiceProvider"
Register an API in a Service Provider:
use Spatie\OpenApiCli\Facades\OpenApiCli;
OpenApiCli::register('https://api.example.com/openapi.yaml', 'example-api')
->baseUrl('https://api.example.com');
Run Commands:
The package auto-generates commands from the OpenAPI spec. For example, a GET /users endpoint becomes:
php artisan example-api:get-users
First Use Case:
php artisan example-api:list
php artisan example-api:get-users --limit=10 --offset=20
php artisan to see auto-generated commands (e.g., example-api:get-users).config/openapi-cli.php for global defaults (e.g., caching, auth).OpenApiCli::register('path/to/spec.yaml', 'api-prefix');
if (app()->environment('staging')) {
OpenApiCli::register('staging-spec.yaml', 'staging-api');
}
->auth(fn () => 'Bearer ' . $this->getAuthToken())
->header('X-Custom-Header', 'value')
->cache(ttl: 3600) // Cache responses for 1 hour
->onError(function ($response, $command) {
if ($response->status() === 404) {
$command->error('Resource not found.');
}
})
->retryOn(function ($response) {
return $response->status() === 429; // Retry on rate limits
}, maxRetries: 3)
->jsonOutput() // or ->yamlOutput()
->showHtmlBody()
handle() method:
OpenApiCli::register('spec.yaml', 'myapp')
->banner('My CLI Tool v1.0');
php myapp get-users --limit=5
Use Laravel’s Http facade for custom logic:
->client(fn () => Http::withOptions(['timeout' => 30]))
Mock the OpenAPI CLI in tests:
$this->partialMock(Spatie\OpenApiCli\Facades\OpenApiCli::class, ['register']);
Load specs dynamically:
$specPath = config("openapi.specs.{$this->app->environment()}");
OpenApiCli::register($specPath, 'env-api');
Extend generated commands by binding them to classes:
OpenApiCli::register('spec.yaml', 'api')
->bindCommand('get-users', UserCommand::class);
Then implement UserCommand to override behavior.
Spec Parsing Errors:
paths or servers) cause silent failures.->debug()
Parameter Name Conflicts:
-, .) may break CLI parsing.--option syntax explicitly:
php artisan api:get-user --user-id=123
->parameterAliases(['user-id' => 'userId'])
Caching Quirks:
->cache(ttl: 60) // 1-minute cache
Authentication Failures:
->retryOn(function ($response) {
return $response->status() === 401;
}, maxRetries: 1)
->onError(function ($response) {
Log::error("Auth failed: {$response->status()}");
})
Command Naming Collisions:
api:list vs. app:list).OpenApiCli::register('spec.yaml', 'api_v2')
Enable Debug Mode:
OpenApiCli::register('spec.yaml', 'api')->debug();
storage/logs/laravel-openapi-cli.log.Inspect Generated Commands:
php artisan to list all commands.app/Console/Kernel.php for registered commands.Validate Specs:
Test Locally:
$this->app->instance(\Illuminate\Http\Client\PendingRequest::class, $mockClient);
Custom Command Classes:
OpenApiCli::register('spec.yaml', 'api')
->bindCommand('get-users', CustomUserCommand::class);
handle() in your class to override logic.Dynamic Spec Loading:
$spec = Storage::disk('s3')->get('specs/api.yaml');
OpenApiCli::register($spec, 'dynamic-api');
Custom Output Formatters:
Spatie\OpenApiCli\Output\OutputFormatter trait to add new formats (e.g., CSV).Pre/Post-Request Hooks:
beforeRequest and afterResponse callbacks:
->beforeRequest(function ($request) {
$request->header('X-Request-ID', Str::uuid());
})
Multi-API Workflows:
OpenApiCli::register('api1.yaml', 'api1')
->register('api2.yaml', 'api2');
Cache Aggressively:
->cache(ttl: 86400) // 24-hour cache
Disable Caching for Dev:
.env:
OPEN_API_CLI_CACHE_ENABLED=false
Parallel Requests:
Http::parallel() in a custom command.Spec Minification:
npx @openapitools/openapi-generator-cli generate -i spec.yaml -g php -o ./ --skip-validate-spec
How can I help you explore Laravel packages today?