Installation:
composer require tsitsishvili/documentator:^1.8
No additional configuration is required for basic usage—Documentator auto-discovers routes under api/* by default.
First Use Case:
/documentation (or /docs if using the docs_path config) to see auto-generated API docs.GET /api/users route with a UserResource will infer:
UserResource).when*/mergeWhen in FormRequests) are now correctly marked as optional instead of nullable.Where to Look First:
config/documentator.php (published via php artisan vendor:publish --tag=documentator-config).
paths, auth, scalar, and new check options for contract validation.php artisan documentator:explain GET /api/users to debug how parameters/fields are inferred.
Use --json for machine-readable output.php artisan documentator:check --against=old-spec.json --fail-on=breaking to enforce backward compatibility.#[Documentation] or #[OpenApi] to override inferred docs (now with improved schema accuracy for resources and Spatie Data).Auto-Inference Workflow (Enhanced):
UserResource).abort(), abort_if(), abort_unless(), and HTTP exceptions (e.g., HttpResponseException).
Example: abort(404, 'User not found') auto-generates a 404 response with the message.when('active', ...)) are now optional (type: object, properties: {...}) instead of nullable.@var types, and examples.
Example: A UserResource with PostResource composition retains all metadata.Optional/Lazy properties and input/output name mapping.
Example: with(['name', 'Optional.email']) generates a schema with name (required) and email (optional).Override and Refine:
#[OpenApi(
responses: [
new Response(
ref: "#/components/schemas/User",
description: "User data",
headers: [new Header(name: "X-RateLimit", schema: new Schema(type: "integer"))]
),
new Response(404, description: "User not found", content: new Content(mediaType: "application/json", schema: new Schema(type: "object", properties: ["error" => ["type" => "string"]]))),
],
security: [["bearerAuth" => []]]
)]
public function show(User $user) { ... }
#[OpenApi(oneOf: [...])] to group distinct responses with the same status code (e.g., 200 OK with different payloads).Authentication:
auth:sanctum) and maps it to OpenAPI securitySchemes.scopes: ["read:users"]) are now inferred from middleware like authorizes:users.Scalar UI Integration:
scalar config:
'scalar' => [
'enabled' => true,
'api_key' => env('SCALAR_API_KEY'),
],
Manual Generation:
php artisan documentator:generate
--fail-on=breaking with documentator:check to enforce contract compatibility:
php artisan documentator:check --against=old-spec.json --fail-on=breaking
storage/app/documentator/openapi.json (configurable).Testing:
Documentator::generate() in tests to verify OpenAPI spec:
$spec = Documentator::generate();
$this->assertArrayHasKey('paths', $spec);
$this->artisan('documentator:check', ['--against' => 'old-spec.json', '--fail-on' => 'breaking'])
->assertExitCode(0); // Fails if breaking changes detected.
Custom Schemas:
config/documentator.php under components.schemas:
'components' => [
'schemas' => [
'Pagination' => [
'type' => 'object',
'properties' => [
'total' => ['type' => 'integer'],
'per_page' => ['type' => 'integer'],
'optional_meta' => ['type' => 'object', 'nullable' => true], // Now correctly marked as optional
],
],
],
],
oneOf for polymorphic responses:
#[OpenApi(
responses: [
new Response(
200,
oneOf: [
new Reference(ref: "#/components/schemas/User"),
new Reference(ref: "#/components/schemas/Team"),
]
)
]
)]
Webhooks/Events:
DocumentatorGenerated event to post-process the spec:
use Tsitsishvili\Documentator\Events\DocumentatorGenerated;
DocumentatorGenerated::listen(function (DocumentatorGenerated $event) {
$event->spec['info']['x-generated-with'] = 'Documentator v1.8.0';
// Add custom validation logic here.
});
documentator:explain to debug inference before extending:
$explanation = $this->artisan('documentator:explain', ['GET', '/api/users'], ['--json' => true])->output();
Laravel Sanctum/Passport:
securitySchemes to the spec.scopes: ["write:posts"]) are inferred from middleware like authorizes:posts,create.Dynamic Routes:
GET /api/users/{user}, Documentator infers:
user (type inferred from route model binding).UserResource with PostResource) preserve field descriptions and examples.#[OpenApi(
parameters: [new Parameter(
name: 'user',
in: 'path',
schema: new Schema(type: 'string', format: 'uuid', description: 'User UUID')
)]
)]
Route Caching:
php artisan route:cache) can cause Documentator to miss new routes.php artisan route:clear
php artisan documentator:generate
Schema Accuracy Changes:
when*/mergeWhen) are optional instead of nullable.abort()/HttpResponseException are included.php artisan documentator:check --against=old-spec.json
Circular References:
User → Post → User) may still cause issues.#[OpenApi(ignore: true)] on problematic properties or simplify schemas.PHPDoc Parsing:
How can I help you explore Laravel packages today?