andrii-hrechyn / auto-documentation
Auto generated documentation for laravel
Package info
github.com/andrii-hrechyn/auto-documentation
pkg:composer/andrii-hrechyn/auto-documentation
Requires
- php: ^8.2
- illuminate/support: ^11.0|^12.0
- symfony/process: ^7.0
- symfony/yaml: ^7.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^2.36|^3.0
- pestphp/pest-plugin-laravel: ^2.4|^3.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-08-29 18:54:04 UTC
README
Generate OpenAPI 3.1 documentation for Laravel APIs with fluent PHP builders, rendered with Redoc.
The typical endpoint is one chain:
Route::post('users.store') ->summary('Create user') ->fromFormRequest() // request body from validation rules, adds a 422 preset ->jsonResponse(UserSchema::make(), 201);
The URI, HTTP verb, {path} parameters, operationId, tag and the auth hint all come from your named Laravel route — you never describe what the framework already knows.
Requirements
- PHP 8.2+
- Laravel 11 or 12
Installation
composer require andrii-hrechyn/auto-documentation php artisan auto-doc:install
The install command creates a docs/ folder (autoloaded as Docs\) with working examples:
docs
├── Components
│ ├── Parameters/ExampleParameter.php
│ └── Schemas/ExampleSchema.php
├── Paths
│ └── testPaths.php
└── info.php
Describing your API
Documentation files return values — no global state:
docs/info.phpreturns a configuredAutoDocbuilder;- every file in
docs/Paths/returns an array ofPathobjects.
// docs/info.php return AutoDoc::make() ->info(Info::make('My API', '1.0.0')) ->servers([Server::make('https://api.example.com')]) ->security(SanctumAuth::make()) ->defaultSecurity(SanctumAuth::make()); // applied to every ->secure() operation
Route-first (recommended)
// docs/Paths/users.php return [ Route::get('users.show') ->summary('Get user') ->jsonResponse(UserSchema::make()), Route::post('users.store') ->summary('Create user') ->fromFormRequest() ->jsonResponse(UserSchema::make(), 201), ];
Explicit composition
Every shortcut expands into the same explicit object graph, which is always available:
return [ Path::make('/orders/{order}') ->method( Method::get() ->summary('Get order') ->tag('orders') ->group('Shop') // Redoc x-tagGroups ->parameter( Parameter::make('order', ParameterIn::PATH) ->required() ->schema(IntegerSchema::make()) ) ->response(SuccessfulResponse::make()->content([ Content::make('application/json')->schema(OrderSchema::make()), ])) ->secure() ), ];
Schemas
Full JSON Schema 2020-12 core: type unions (->nullable()), oneOf/anyOf/allOf/not with discriminators, additionalProperties, const, pattern, numeric and length constraints:
ObjectSchema::make([ StringProperty::make('status')->enum(OrderStatus::class)->required(), NumberProperty::make('total')->minimum(0)->required(), StringProperty::make('note')->nullable(), ])->additionalProperties(false); CompositeSchema::oneOf([CardPayment::make(), CashPayment::make()]) ->discriminator('type');
Or infer a response schema from a real payload — the example is attached automatically and all keys become required:
->jsonResponse(Schema::fromExample([ 'id' => 1, 'name' => 'Ann', 'deleted_at' => null, ]))
Reusable schemas, parameters and responses extend the classes in AutoDocumentation\Components and are emitted under components with $ref automatically. Presets ship for common responses: UnauthorizedResponse (401), ForbiddenResponse (403), ValidationErrorResponse (422, Laravel error shape).
For API Resources, the recommended convention is one SchemaComponent per resource, referenced from every endpoint that returns it — the contract test below keeps the component honest against the real output.
Custom validation rules
fromFormRequest() maps standard Laravel rules out of the box. Register mappers for your own rules — by class for Rule objects, by name for string rules (rule arguments arrive in the matched string):
// e.g. in a service provider ValidationRuleParser::extend(PhoneNumber::class, fn () => StringSchema::make()->pattern('^\+\d{10,15}$')); ValidationRuleParser::extend('currency', fn (string $rule) => StringSchema::make()->enum(explode(',', Str::after($rule, ':'))));
A matched extension owns the field's schema; required and nullable handling still applies on top.
Generating and serving
php artisan auto-doc:generate # writes storage/app/auto-docs/documentation.yaml
The Redoc UI is served at /api/doc (spec at /api/doc/spec) in the environments listed in the config. Set AUTO_DOCUMENTATION_GENERATE_ALWAYS=true locally to regenerate on every page load. Publish the config with:
php artisan vendor:publish --tag=auto-documentation
Keeping the documentation honest
Lint the spec structurally (missing responses, parameter/URI mismatches, dangling $refs, unregistered security schemes and more):
php artisan auto-doc:lint # exit code 1 on errors php artisan auto-doc:lint --strict # warnings fail too
Contract-test real responses against the documentation in your feature tests:
use AutoDocumentation\Testing\AssertsApiDoc; $response = $this->getJson('/api/users/1'); $this->assertResponseMatchesApiDoc($response, '/api/users/{user}', 'get');
A response that drifts from its documented schema — wrong type, missing required field, undocumented status — fails the test with a field-level diff.
Testing
vendor/bin/pest
License
This library is licensed under the MIT License. See the LICENSE file for details.
Credits
- Developer: Andriy Hrechyn
- Email: andriy.hrechyn@gmail.com