jkbennemann / laravel-api-documentation
This is an opinionated package to generate API documentation for your Laravel application.
Requires
- php: ^8.2
- illuminate/contracts: ^10.0 || ^11.0 || ^12.0
- nikic/php-parser: ^5.3
- php-openapi/openapi: ^2.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^9.0.0||^8.22.0
- pestphp/pest: ^2.34
- pestphp/pest-plugin-arch: ^2.7
- pestphp/pest-plugin-laravel: ^2.3
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1
- phpstan/phpstan-phpunit: ^1.3
- spatie/laravel-data: ^4.11
- spatie/laravel-ray: ^1.35
README
Overview
Laravel API Documentation is a powerful package that automatically generates OpenAPI 3.0 documentation from your Laravel application code. It eliminates the need to manually write and maintain API documentation by intelligently analyzing your routes, controllers, requests, and responses.
Key Features
- Zero-Config Operation: Works out of the box with standard Laravel conventions
- Automatic Route Analysis: Scans all routes and extracts path parameters, HTTP methods, and middleware
- Smart Request Analysis: Extracts validation rules from FormRequest classes to document request parameters
- Dynamic Response Detection: Analyzes controller return types and method bodies to document responses
- Spatie Data Integration: First-class support for Spatie Laravel Data DTOs
- Resource Collection Support: Handles JsonResource and ResourceCollection responses
- Attribute Enhancement: Optional PHP 8 attributes for additional documentation control
Installation
1. Install via Composer
composer require jkbennemann/laravel-api-documentation
2. Publish Configuration (Optional)
php artisan vendor:publish --tag="api-documentation-config"
3. Link Storage Directory
The package stores documentation in your storage directory. Make it accessible with:
php artisan storage:link
Configuration
Default Settings
Out of the box, the package:
- Ignores vendor routes and
HEAD
/OPTIONS
methods - Disables Swagger/ReDoc UIs by default (can be enabled in config)
- Stores documentation at
storage/app/public/api-documentation.json
Documentation Storage
To include the generated documentation in version control, update your .gitignore
:
# storage/app/public/.gitignore * !.gitignore !api-documentation.json
Custom Storage Location
For a more accessible location, add a custom disk in config/filesystems.php
:
'documentation' => [ 'driver' => 'local', 'root' => public_path('docs'), 'url' => env('APP_URL') . '/docs', 'visibility' => 'public', ],
Then update your config:
// config/laravel-api-documentation.php 'storage' => [ 'disk' => 'documentation', 'filename' => 'api-documentation.json', ],
CI/CD Integration
Add documentation generation to your deployment workflow:
# In your deployment script
php artisan documentation:generate
Or add to your composer.json
scripts:
"scripts": { "post-deploy": [ "@php artisan documentation:generate" ] }
Usage
Generating Documentation
php artisan documentation:generate
This command scans your application routes and generates an OpenAPI 3.0 specification file at your configured location.
Viewing Documentation
By default, the documentation is accessible at:
/documentation
- Default UI (Swagger if enabled)/documentation/swagger
- Swagger UI (if enabled)/documentation/redoc
- ReDoc UI (if enabled)
To enable the UIs, update your configuration:
// config/laravel-api-documentation.php 'ui' => [ 'enabled' => true, 'swagger' => true, 'redoc' => true, ],
Specifying Files to Generate
Generate documentation for specific files only:
php artisan documentation:generate --file=api-v1
This generates api-v1.json
based on your configuration settings.
How It Works
The package analyzes your Laravel application using several intelligent components:
- Route Analysis: Scans all registered routes to identify controllers, HTTP methods, and path parameters
- Controller Analysis: Examines controller methods to determine response types and structures
- Request Analysis: Processes FormRequest classes to extract validation rules and convert them to OpenAPI parameters
- Response Analysis: Detects return types and analyzes method bodies to determine response structures
Key Features
Zero-Configuration Detection
The package automatically detects and documents your API with minimal configuration:
Response Type Detection
- Analyzes controller return types (
JsonResponse
,ResourceCollection
, etc.) - Examines method bodies when return types aren't declared
- Supports union types (
@return UserData|AdminData
) - Generates proper paginated response structures with
data
,meta
, andlinks
Controller Support
- Works with traditional and invokable controllers
- Processes class-level and method-level attributes
- Handles mixed controller architectures seamlessly
Request Parameter Extraction
- Extracts validation rules from FormRequest classes
- Detects route parameters (
{id}
,{user}
) automatically - Supports nested parameter structures (
user.profile.name
) - Handles parameters merged from route values in
prepareForValidation
Validation & Type Detection
- Converts Laravel validation rules to OpenAPI types and formats
- Intelligently determines required vs. optional parameters
- Maps validation rules to appropriate formats (
email
→string
withemail
format)
Resource & Collection Support
- Distinguishes between arrays and object responses
- Analyzes ResourceCollection for contained DTO types
- Supports
DataCollectionOf
attributes for nested collections
Recent Enhancements
Route Parameter Handling
- Route Value Detection: Properly handles parameters merged from route values in
prepareForValidation
- Parameter Exclusion: Supports the
IgnoreDataParameter
attribute to exclude fields from body parameters
Spatie Data Integration
- Clean Schema Generation: Excludes internal Spatie Data fields (
_additional
and_data_context
) from documentation - DataCollectionOf Support: Properly documents nested collection structures with correct item types
- Union Type Support: Handles PHP 8+ union types in Spatie Data objects
Dynamic Response Analysis
- JsonResource Analysis: Improved detection of dynamic properties in JsonResource responses
- Method Body Parsing: Enhanced analysis of controller method bodies for response structure detection
- Paginated Response Support: Accurate documentation of paginated responses with proper structure
For more information on the OpenAPI specification, see OpenAPI Specification.
Enhancing Documentation with Attributes
While the package works automatically, you can enhance your documentation using PHP 8 attributes.
Controller Method Attributes
use JkBennemann\LaravelApiDocumentation\Attributes\Tag; use JkBennemann\LaravelApiDocumentation\Attributes\Summary; use JkBennemann\LaravelApiDocumentation\Attributes\Description; use JkBennemann\LaravelApiDocumentation\Attributes\AdditionalDocumentation; use JkBennemann\LaravelApiDocumentation\Attributes\DataResponse; #[Tag('Authentication')] #[Summary('Login a user')] #[Description('Logs a user in with email and password credentials.')] #[AdditionalDocumentation(url: 'https://example.com/auth', description: 'Auth documentation')] #[DataResponse(200, description: 'Logged in user information', resource: UserResource::class)] #[DataResponse(401, description: 'Failed Authentication', resource: ['error' => 'string'])] public function login(LoginRequest $request) { // Method implementation }
Available parameters:
- (required)
status
(int) - The status code of the response description
(string) - A description of the response; default:''
resource
(null | string | array) - The resource class or Spatie Data object class that is returned by the route (e.g.UserResource::class
,['id' => 'string']
,null
); default:[]
headers
(null | array) - An array of response headers that are returned by the route (e.g.['X-Token' => 'string']
); default:[]
# SampleController.php use JkBennemann\LaravelApiDocumentation\Attributes\DataResponse; //.. #[DataResponse(200, description: 'Logged in user information', resource: UserResource::class, headers: ['X-Token' => 'Token for the user to be used to issue API calls',])] #[DataResponse(401, description: 'Failed Authentication', resource: ['error' => 'string'])] public function index() { //... }
This will add a new field to the route object in the OpenAPI file:
{ //... "\/login": { "post": { //... "responses": { "200": { "description": "Logged in user information", "headers": { "X-Token": { "description": "Token for the user to be used to issue API calls", "schema": { "type": "string" } } }, "content": { "application\/json": { "schema": { //data of the UserResource.php } } } }, "401": { "description": "Failed Authentication", "headers": {}, "content": { "application\/json": { "schema": { "type": "object", "properties": { "error": { "type": "string" } } } } } } } //... } } }
Request/Resource attributes
For request or resource classes the same attributes can be used as for the routes, except for the Tag
attribute.
In addition to that the following attributes are available:
1. PathParameter
This attribute can be used to specify additional information about path parameters in your routes.
It can be applied to controller methods to enhance the documentation of route parameters like {id}
, {user}
, etc.
Available parameters:
- (required)
name
(string) - The name of the path parameter (must match the route parameter) required
(boolean) - Whether the parameter is required or not; default:true
description
(string) - A description of the parameter; default:''
type
(string) - The type of the parameter; default:'string'
format
(string) - The format of the parameter, considered as the sub-type as of OpenAPI; default:null
example
(mixed) - An example value for the parameter; default:null
# UserController.php use JkBennemann\LaravelApiDocumentation\Attributes\PathParameter; //.. #[PathParameter(name: 'id', type: 'string', format: 'uuid', description: 'The user ID', example: '123e4567-e89b-12d3-a456-426614174000')] #[PathParameter(name: 'status', type: 'string', description: 'Filter users by status', example: 'active')] public function show(string $id, string $status) { //... }
2. Parameter
This attribute can be used to specify additional information about request or response parameters.
It can be applied at both class level and method level (e.g., on the rules()
method of FormRequest classes).
Available parameters:
- (required)
name
(string) - The name of the parameter required
(boolean) - Whether the parameter is required or not; default:false
description
(string) - A description of the parameter; default:''
type
(string) - The type of the parameter; default:'string'
format
(string) - The format of the parameter, considered as the sub-type as of OpenAPI; default:null
example
(mixed) - An example value for the parameter; default:null
deprecated
(boolean) - Whether the parameter is deprecated or not; default:false
Method Level Usage (FormRequest):
# LoginUserRequest.php use JkBennemann\LaravelApiDocumentation\Attributes\Parameter; //.. #[Parameter(name: 'email', required: true, format: 'email', description: 'The email of the user', example: 'hello@example.com')] #[Parameter(name: 'password', required: true, description: 'The password of the user')] #[Parameter(name: 'confirm_token', required: true, description: 'The confirmation token. This is not used any longer!', deprecated: true)] public function rules(): array { return [ 'email' => [ 'required', 'email', ], 'password' => 'required', ]; }
Class Level Usage (Resource):
# UserResource.php use JkBennemann\LaravelApiDocumentation\Attributes\Parameter; #[Parameter(name: 'id', type: 'string', format: 'uuid', description: 'The user ID', example: '123e4567-e89b-12d3-a456-426614174000')] #[Parameter(name: 'email', type: 'string', format: 'email', description: 'The users email address')] #[Parameter(name: 'attributes', type: 'array', description: 'Additional attributes assigned to the user', example: [])] public function toArray($request): array|JsonSerializable|Arrayable { return [ 'id' => $this->id, 'email' => $this->email, 'attributes' => $this->userAttributes ?? [], ]; }
📋 Query Parameter Annotations
In addition to attributes, the package supports @queryParam
annotations for documenting query parameters:
# UserController.php /** * Get a list of users * * @queryParam per_page integer Number of users per page. Example: 15 * @queryParam search string Search term for filtering users. Example: john * @queryParam status string Filter by user status. Example: active */ public function index(Request $request) { //... }
This automatically generates query parameter documentation in the OpenAPI specification.
💡 Usage Examples & Best Practices
Here are some comprehensive examples showing how to leverage the automatic detection features:
Example 1: Complete Controller with Automatic Detection
<?php namespace App\Http\Controllers; use App\Http\Requests\CreateUserRequest; use App\Http\Resources\UserResource; use App\Models\User; use Illuminate\Http\JsonResponse; use Illuminate\Http\Resources\Json\ResourceCollection; use JkBennemann\LaravelApiDocumentation\Attributes\{Tag, Summary, Description, PathParameter, DataResponse}; #[Tag('Users')] class UserController extends Controller { /** * Get a paginated list of users * * @queryParam per_page integer Number of users per page. Example: 15 * @queryParam search string Search term for filtering users. Example: john * @queryParam status string Filter by user status. Example: active * * @return ResourceCollection<UserResource> */ #[Summary('List all users')] #[Description('Retrieves a paginated list of users with optional filtering capabilities')] public function index(Request $request): ResourceCollection { $users = User::query() ->when($request->search, fn($q) => $q->where('name', 'like', "%{$request->search}%")) ->when($request->status, fn($q) => $q->where('status', $request->status)) ->paginate($request->per_page ?? 15); return UserResource::collection($users); } /** * Get a specific user by ID */ #[PathParameter(name: 'id', type: 'string', format: 'uuid', description: 'The user ID', example: '123e4567-e89b-12d3-a456-426614174000')] #[DataResponse(200, description: 'User found successfully', resource: UserResource::class)] #[DataResponse(404, description: 'User not found', resource: ['message' => 'string'])] public function show(string $id): UserResource|JsonResponse { $user = User::findOrFail($id); return new UserResource($user); } /** * Create a new user */ #[Summary('Create user')] #[DataResponse(201, description: 'User created successfully', resource: UserResource::class)] #[DataResponse(422, description: 'Validation failed')] public function store(CreateUserRequest $request): UserResource { $user = User::create($request->validated()); return new UserResource($user); } }
Example 2: Advanced FormRequest with Nested Parameters
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use JkBennemann\LaravelApiDocumentation\Attributes\Parameter; class CreateUserRequest extends FormRequest { #[Parameter(name: 'name', required: true, description: 'The full name of the user', example: 'John Doe')] #[Parameter(name: 'email', required: true, format: 'email', description: 'Unique email address', example: 'john@example.com')] #[Parameter(name: 'profile.bio', description: 'User biography', example: 'Software developer with 5 years experience')] #[Parameter(name: 'profile.avatar', type: 'string', format: 'uri', description: 'Avatar image URL')] #[Parameter(name: 'preferences.notifications', type: 'boolean', description: 'Enable email notifications', example: true)] public function rules(): array { return [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'email', 'unique:users'], 'profile.bio' => ['nullable', 'string', 'max:1000'], 'profile.avatar' => ['nullable', 'url'], 'preferences.notifications' => ['boolean'], 'preferences.theme' => ['string', 'in:light,dark'], ]; } }
Example 3: Invokable Controllers with Class-Level Attributes
Laravel's invokable controllers (single-action controllers) are fully supported with class-level attribute processing:
<?php namespace App\Http\Controllers; use App\Http\Requests\CreatePostRequest; use App\Http\Resources\PostResource; use App\Models\Post; use Illuminate\Http\JsonResponse; use JkBennemann\LaravelApiDocumentation\Attributes\{Tag, Summary, Description, DataResponse}; #[Tag('Posts')] #[Summary('Create a new blog post')] #[Description('Creates a new blog post with the provided content and metadata')] #[DataResponse(PostResource::class, 201, 'Post created successfully')] class CreatePostController extends Controller { /** * Handle the incoming request to create a new post. * * @param CreatePostRequest $request * @return JsonResponse */ public function __invoke(CreatePostRequest $request): JsonResponse { $post = Post::create($request->validated()); return PostResource::make($post) ->response() ->setStatusCode(201); } }
Key Features for Invokable Controllers:
- Class-Level Attributes:
#[Tag]
,#[Summary]
,#[Description]
placed on the class are automatically detected - Automatic Route Processing: Both
Controller@method
andController
(invokable) route formats supported - Response Type Detection: Same automatic detection as traditional controllers
- Request Validation: FormRequest classes processed normally
- Mixed Controller Support: Traditional and invokable controllers work seamlessly together
Route Registration:
// Traditional route registration for invokable controllers Route::post('/posts', CreatePostController::class); // Mixed with traditional controllers Route::get('/posts', [PostController::class, 'index']); Route::post('/posts', CreatePostController::class); // Invokable Route::get('/posts/{id}', [PostController::class, 'show']);
Example 4: Resource with Spatie Data Integration
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; use JkBennemann\LaravelApiDocumentation\Attributes\Parameter; class UserResource extends JsonResource { #[Parameter(name: 'id', type: 'string', format: 'uuid', description: 'Unique user identifier')] #[Parameter(name: 'name', type: 'string', description: 'Full name of the user')] #[Parameter(name: 'email', type: 'string', format: 'email', description: 'User email address')] #[Parameter(name: 'profile', type: 'object', description: 'User profile information')] #[Parameter(name: 'created_at', type: 'string', format: 'date-time', description: 'Account creation timestamp')] public function toArray($request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'profile' => [ 'bio' => $this->profile?->bio, 'avatar' => $this->profile?->avatar, ], 'preferences' => [ 'notifications' => $this->preferences['notifications'] ?? true, 'theme' => $this->preferences['theme'] ?? 'light', ], 'created_at' => $this->created_at, 'updated_at' => $this->updated_at, ]; } }
Example 5: Union Types with Multiple Response Formats
<?php namespace App\Http\Controllers; use App\DTOs\UserData; use App\DTOs\AdminData;
🎯 Best Practices
- Leverage Automatic Detection: Let the package automatically detect response types and validation rules
- Use Attributes for Enhancement: Add
#[Parameter]
and#[PathParameter]
attributes only when you need to provide additional context - Document Complex Scenarios: Use
@queryParam
annotations for query parameters and union return types for multiple response formats - Structured Validation: Use nested validation rules for complex request structures
- Consistent Naming: Use consistent parameter naming across your API for better documentation
Roadmap
✅ Completed Features
- Advanced Response Type Detection: Automatic detection of return types, union types, and method body analysis
- Smart Request Parameter Extraction: FormRequest validation rule processing and parameter attribute support
- Invokable Controller Support: Full support for Laravel invokable controllers with class-level attribute processing
- Path Parameter Documentation:
#[PathParameter]
attribute for route parameter enhancement - Query Parameter Support:
@queryParam
annotation processing - Nested Parameter Handling: Complex nested parameter structures with proper grouping
- Spatie Data Integration: Full support for Spatie Data objects with automatic schema generation
- Resource Collection Intelligence: Smart detection of collection types and pagination
- Union Type Processing: DocBlock union type analysis with
oneOf
schema generation - Class Name Resolution: Automatic resolution of short class names to fully qualified names
- Validation Rule Conversion: Laravel validation rules to OpenAPI type conversion
🚀 Planned Enhancements
- Enhanced Examples: More comprehensive example generation for request/response bodies
- Custom Validation Rules: Support for custom Laravel validation rules
- Advanced Response Headers: Automatic detection of response headers from controller methods
- File Upload Documentation: Automatic detection and documentation of file upload endpoints
- Middleware Documentation: Enhanced middleware detection and security scheme generation
- Custom Storage Options: Support for external storages (e.g., GitHub, S3 Bucket, etc.)
- Multi-version API Support: Support for API versioning in documentation
- Performance Optimization: Caching mechanisms for large applications
- Integration Testing: Built-in API testing capabilities based on generated documentation
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.