Laravel API documentation generating tool
johnylemon/laravel-apidocs is a Laravel package for laravel api documentation generating tool.
It currently has 46 GitHub stars and 2.790 downloads on Packagist (latest version 1.1.0).
Install it with composer require johnylemon/laravel-apidocs.
Discover more Laravel packages by johnylemon
or browse all Laravel packages to compare alternatives.
Last updated
I don't like writing tons of lines of stupid annotations just to have hope that api documentation will be generated correctly without errors that says nothing. And I am not the only one. More.
This package solves this problem the way I like - by writing PHP code.
This package adds apidocs method to Laravel routes, where you can define route definitions using code you use every day.
This way you can:

johnylemon/laravel-apidocs repositorycomposer require johnylemon/laravel-apidocs
Register Johnylemon\Apidocs\Providers\ApidocsServiceProvider provider if not registered automagically .
Install package. This command will publish all required assets.
php artisan apidocs:install
This package ships with command for rapid route definition generation.
php artisan apidocs:endpoint SampleEndpoint
Brand new SampleEndpoint class will be placed within app\Apidocs\Endpoints directory.
Target directory may be changed within your apidocs config file.
This class contains only one describe method, where you have to use any of available methods that will describe your endpoint. Like that:
<?php
namespace App\Apidocs\Endpoints;
use Johnylemon\Apidocs\Endpoints\Endpoint;
use Johnylemon\Apidocs\Facades\Param;
class SampleEndpoint extends Endpoint
{
public function describe(): void
{
$this->title('List users')
->desc('Returns paginated list of users');
}
}
As you can see we set title and description as endpoint definition. Every method returns endpoint instance so you can chain them.
Set uri. Called under the hood during endpoint mounting
$this->uri('/users');
Set endpoint method. Called under the hood during endpoint mounting
$this->method('POST');
Add endpoint to specific group. Group have to be defined previously.
$this->group('some-group-slug');
Will mark endpoint as deprecated.
$this->deprecated();
Set endpoint title
$this->title('Create user resource');
Set endpoint description
$this->description('This endpoint contains logic for creating user resources based on provided data');
Alias for description
Defines endpoint query params. See: parameters
$this->query([
'page' => Param::type('int')
])
Defines endpoint route params. See: parameters
$this->query([
'page' => Param::type('int')
])
Defines endpoint body params. See: parameters
$this->query([
'page' => Param::type('int')
])
Defines endpoint header
$this->header('x-johnylemon', 'apidocs')
Defines multiple endpoint header at once
$this->headers([
'x-johnylemon' => 'apidocs',
'x-laravel' => 'framework'
])
Defines endpoint example. Optionally you can define example title
$this->example([
'name' => 'johnylemon',
'web' => 'https://johnylemon.dev',
'email' => '[email protected]'
], 'Store user')
Define multiple endpoint examples at once
$this->examples([
[
'name' => 'johny',
'web' => 'https://johnylemon.dev',
'email' => '[email protected]'
],
[
'name' => 'lemon',
'web' => 'https://johnylemon.dev',
'email' => '[email protected]'
]
])
Define sample return value with status code. OPtinally you may define response description.
$this->returns(201, [
'name' => 'johny',
'web' => 'https://johnylemon.dev',
'email' => '[email protected]'
], 'User created')
->returns(401, [
'status' => 'unauthorized',
], 'Auth issue');
Additionally you can use methods like returns201 (or any other status code)
// calling this ...
$this->returns201([
'name' => 'johny',
'web' => 'https://johnylemon.dev',
'email' => '[email protected]'
], 'User created');
// ... is equivalent of this...
$this->returns(201, [
'name' => 'johny',
'web' => 'https://johnylemon.dev',
'email' => '[email protected]'
], 'User created')
Okay, you created your first endpoint definition. Now it's time to use it as some real route definition.
Lets assume you have following routes:
Route::get('api/users', [UsersController::class, 'index']);
If you want to use App\Apidocs\Endpoints\SampleEndpoint class as definition for first of them you should simply do this:
use App\Apidocs\Endpoints\SampleEndpoint;
Route::get('api/users', [UsersController::class, 'index'])->apidocs(SampleEndpoint::class);
and... yes, thats it!
The only thing you have to do now is to call php artisan apidocs:generate command and visit /apidocs route to see it in action!
:warning: This package must clear route cache to generate apidocs properly. If you are using route caching in your production environment rememeber to call
artisan route:cacheafterartisan apidocs:generatecommand
Because apidocs method returns endpoint class, you can chain methods during route definition. For example, you may want to mark your route as deprecated:
use App\Apidocs\Endpoints\SampleEndpoint;
Route::get('api/users', [UsersController::class, 'index'])->apidocs(SampleEndpoint::class)->deprecated();
And because deprecated method returns endpoint as well, you are allowed to use other endpoint methods.
:warning: After calling
apidocsmethod you cannot use route-specific methods, like, say,namemethod. Be sure to callapidocsmethod after all framework route-specific methods are called.
Sometimes you would like to use resource or apiResource methods to create bunch of typical CRUD endpoints. To specify definitions for these endpoints you have to use their names:
Route::resource('posts', PostsController::class)->apidocs([
'posts.index' => PostsIndexEndpoint::class,
'posts.store' => PostStoreEndpoint::class,
]);
As you can see, you may ommit endpoints you dont want to be documented.
Sometimes you may be using resources or apiResources methods to create bunch of CRUDs at once. Because Laravel does not provide any handy hook for that, routes defined that way (and any other named routes!) may be documented using apidocs helper:
//
// your resoures
//
Route::resources([
'users' => UsersController::class,
'posts' => PostsController::class,
]);
//
// defining endpoints
//
apidocs([
'posts.index' => PostsIndexEndpoint::class,
'posts.store' => PostStoreEndpoint::class,
'users.index' => UsersIndexEndpoint::class,
'users.store' => UserStoreEndpoint::class,
'users.destroy' => UserStoreEndpoint::class,
]);
As metioned earlier, you may ommit endpoints you don't want to be documented.
Some routes contains route parameters, like {user} segment.
Sometimes you also want to use required or optional query parameters.
Routes like POST, PATCH, PUT almost always expects some payload.
You can define them using params, and pass them as array to query, body and params method when describing endpoint.
Lets assume your index route from previously presented routes expects optional page parameter.
Your definition should now contain additional query method call with array of possible parameters. After that your code will look like that:
<?php
namespace App\Apidocs\Endpoints;
use Johnylemon\Apidocs\Endpoints\Endpoint;
use Johnylemon\Apidocs\Facades\Param;
class SampleEndpoint extends Endpoint
{
public function describe(): void
{
$this->title('List users')
->desc('Returns paginated list of users')
->query([
Param::int('page')->example(1)->default(1)->optional()
])
}
}
Note that we did not specify parameter name (page) by array key. It is not necessary when you define parameter name within class. But of course you can define them in different way:
use Johnylemon\Apidocs\Facades\Param;
$this->query([
// parameter name will be `page`
Param::int('page')->example(1)->default(1)->optional()
// same effect:
'page' => Param::int('page')->example(1)->default(1)->optional()
// same effect:
'page' => Param::type('int')->example(1)->default(1)->optional()
// this parameter will be named `page_number`
'page_number' => Param::int('page')->example(1)->default(1)->optional()
])
As you can see, when parameter name is defined in both, array key and param name, array key will take precedence allowing you to create reusable custom parameters.
Route parameters and request body parameters can be defined same way.
Define parameter type
Param::type('int');
Define parameter name
Param::name('username');
Define parameter description
Param::description('Unique username');
Alias of description. See description
Mark parameter as required
Param::required();
Mark parameter as optional
Param::optional();
Set parameter possible values
Param::possible([10, 100, 1000]);
Alias for possible. See possible
Param::enum([10, 100, 1000]);
Set parameter default value.
Param::default(42);
Set parameter example.
Param::example(42);
Alias for example. See example
Param class makes use of magic __call method and allow you to define parameter type and name at once by using one of these methods: string, array, boolean, bool, integer or int
use Johnylemon\Apidocs\Facades\Param;
$this->query([
Param::string('slug'), // `slug` property, that should have `string` type
Param::int('id'), // id `property`, that should have `int` type
Param::array('roles'), // `roles` property, that should have `array` type
])
It is common case that you may use page or some other param in different endpoint definitions. So it may be cumbersome to write something like that over and over again:
$this->query([
Param::int('page')->example(1)->default(1)->optional()
]);
To solve that problem you may define PageParam, which you can reuse as many times as you want without repeated code:
use App\Apidocs\Params\PageParam;
(...)
$this->query([
PageParam::class
]);
Custom parameters may be created by typing
php artisan apidocs:param PageParam
New param class may be defined within __construct method:
<?php
namespace App\Apidocs\Params;
use Johnylemon\Apidocs\Params\Param;
class PageParam extends Param
{
public function __construct()
{
$this->name('page')->type('int')->default(1)->eg(42)->optional();
}
}
Apidocs endpoints will be groupped. If no group is specified, default non-groupped group will be used.
You can define your own groups using Johnylemon\Apidocs\Facades\Apidocs facade:
use Johnylemon\Apidocs\Facades\Apidocs;
Apidocs::defineGroup('users', 'Users', 'Manage users');
Apidocs::defineGroup('tickets', 'Tickets'); // Last parameter is optional
Groups must be defined before route registering. Perfect place for that is the the very beginning of your routes file.
This package ships with some commands that will be used for common tasks:
| command | description |
|---------------------------|-----------------------|
| apidocs:install | install package |
| apidocs:endpoint {name} | create endpoint class |
| apidocs:param {name} | create param class |
You can run the tests with:
vendor/bin/phpunit
The MIT License (MIT) Please see LICENSE for details.
Visit me at https://johnylemon.dev
Developed with ❤ by johnylemon.