Swagger Bake
A delightfully tasty plugin for generating OpenAPI, Swagger and Redoc
Automatically generate OpenApi, Swagger, and Redoc documentation from your existing CakePHP code
- Creates OpenApi paths and operations from your RESTful routes and controllers.
- Creates OpenAPI Schema from your Entities and Tables.
- Integrates with: Paginator, friendsofcake/search, Validator, and Bake.
- Provides additional functionality through Attributes and Doc Blocks.
Check out the demo applications for examples.
Demos | Source |
---|---|
Swagger Bake Demo (v2) | https://github.com/cnizzardini/cakephp-swagger-bake-demo |
Swagger Bake Demo (v1) | https://github.com/cnizzardini/cakephp-swagger-bake-demo/tree/1.next |
Swagger/MixerAPI Demo (v1) | https://github.com/mixerapi/demo |
This is built for CakePHP 4.x only. Supported versions:
Version | Branch | Cake Version | PHP Version |
---|---|---|---|
2.* | master | ^4.2 | 8.0+ |
1.* | 1.next | ^4.0 | 7.2+ |
Table of Contents
- Installation
- Getting Started
- Attributes
- Events
- Customizing Exception Responses
- Extending Views and Controllers
- Multiple Instances of SwaggerBake
- Debug Commands
- Bake Theme
- Common Issues
- Contributing
Installation
SwaggerBake requires CakePHP4 and a few dependencies that will be automatically installed via composer.
composer require cnizzardini/cakephp-swagger-bake
Run bin/cake plugin load SwaggerBake
or manually load the plugin:
# src/Application.php
public function bootstrap(): void
{
// other logic...
$this->addPlugin('SwaggerBake');
}
For standard applications that have not split their API into plugins, the automated setup should work. Otherwise use the manual setup.
Automated Setup
Run the installer:
bin/cake swagger install
Then load the config and add a route.
Manual Setup
-
Create a base swagger.yml file at
config\swagger.yml
. An example file is provided here. -
Create a swagger_bake.php config file at
config/swagger_bake.php
file. See the example file here for further explanation. Then just add a route.
For more read sections on Multiple Instances of SwaggerBake and Extending Views and Controllers
Load the config
In your config/bootstrap.php
file:
Configure::load('swagger_bake', 'default', false);
Add Route
Create a route for the SwaggerUI page in config/routes.php
, example:
$builder->connect(
'/api',
['plugin' => 'SwaggerBake', 'controller' => 'Swagger', 'action' => 'index']
);
You can now browse to either /api
for swagger or /api?doctype=redoc
for redoc. Your OpenAPI JSON
will exist at /api/swagger.json
.
Getting Started
- You can generate OpenAPI json from the command line at anytime by running:
bin/cake swagger bake
-
If Hot Reload is enabled (see config) OpenAPI will be generated each time you browse to SwaggerUI (or Redoc) in your web browser.
-
You can also generate OpenAPI programmatically:
$swagger = (new \SwaggerBake\Lib\SwaggerFactory())->create();
$swagger->getArray(); # returns swagger array
$swagger->toString(); # returns swagger json
$swagger->writeFile('/full/path/to/your/swagger.json'); # writes swagger.json
- Checkout the debug commands for troubleshooting and the bake theme for generating RESTful controllers.
Routes
Your RESTful routes are used to build OpenAPI paths and operations.
Controllers
SwaggerBake will parse the DocBlocks on your controller actions for additional OpenAPI data.
/**
* OpenAPI Operation Summary
*
* This displays as the operations long description
*
* @link https://book.cakephp.org/4/en/index.html External documentation
* @deprecated Indicates the operation is deprecated
* @throws \Cake\Http\Exception\BadRequestException Appears as 400 response with this description
* @throws \Exception Appears as 500 response with this description
*/
public function index() {}
If you prefer, you may use the OpenApiOperation, OpenApiResponse attributes instead. These attributes take precedence over doc block parsing. Read below for a full list of attributes.
Models
OpenAPI schema is built from your Table and Entity classes and any validators you've defined in them. You may adjust the default schema using the OpenApiSchema and OpenApiSchemaProperty attributes.
Attributes
For additional functionality the following PHP8 Attributes
may be used. These can be imported individually from the SwaggerBake\Lib\Attribute
namespace.
Read the Attributes docs for detailed examples. If you are using
version 1 you will need to use annotations.
Attribute | Usage | Description |
---|---|---|
OpenApiDto | Controller Action | Builds OpenAPI query params and request bodies from Data Transfer Objects |
OpenApiForm | Controller Action | Builds OpenAPI for application/x-www-form-urlencoded request bodies |
OpenApiHeader | Controller Action | Create OpenAPI header parameters |
OpenApiOperation | Controller Action | Modifies OpenAPI operation |
OpenApiPaginator | Controller Action | Create OpenAPI query params from CakePHP Paginator Component |
OpenApiPath | Controller | Modifies OpenAPI paths |
OpenApiPathParam | Controller Action | Modify an existing OpenAPI path parameter |
OpenApiQueryParam | Controller Action | Builds OpenAPI query param |
OpenApiRequestBody | Controller Action | Modify OpenAPI request body |
OpenApiResponse | Controller Action | Modify OpenAPI response |
OpenApiSchema | Entity | Modifies OpenAPI schema |
OpenApiSchemaProperty | Entity or Class | Modifies an OpenAPI schema property or defines OpenApiResponse schema |
OpenApiSearch | Controller Action | Create OpenAPI query params from CakePHP Search plugin |
OpenApiSecurity | Controller Action | Create/modify OpenAPI security |
~~OpenApiDtoQuery~~ | DTO class property | Builds OpenAPI query param from Data Transfer Objects (deprecated, use OpenApiQueryParam in v2.2.5+) |
~~OpenApiDtoRequestBody~~ | DTO class property | Builds OpenAPI request body property from Data Transfer Objects (deprecated, use OpenApiSchemaProperty in v2.2.5+) |
Event System
SwaggerBake comes with an event system to allow for further control over your OpenAPI schema.
Event | Description |
---|---|
SwaggerBake.Operation.created | Dispatched each time an OpenAPI Path > Operation is created |
SwaggerBake.Path.created | Dispatched each time an OpenAPI Path is created |
SwaggerBake.Schema.created | Dispatched each time an OpenAPI Schema is created |
SwaggerBake.initialize | Dispatched during initialization phase on SwaggerBake |
SwaggerBake.beforeRender | Dispatched before SwaggerBake outputs OpenAPI JSON |
Customizing Exception Response Samples
By default, SwaggerBake uses '#/components/schemas/Exception'
as your OpenAPI documentations Exception schema. See the
default swagger.yml and exceptionSchema
in swagger_bake.php for more
info. You can further customize with attributes and @throws
.
OpenApiResponse
Using the ref
or schema
properties of OpenApiResponse.
Using the @throws
tag and OpenApiExceptionSchemaInterface
Implement SwaggerBake\Lib\OpenApiExceptionSchemaInterface
on your exception class, then document
the exception with a @throws
tag in your controller action's doc block.
/**
* @throws \App\Exception\MyException
*/
public function add(){}
Example exception class:
class MyException implements OpenApiExceptionSchemaInterface
{
public static function getExceptionCode(): string
{
return '400';
}
public static function getExceptionDescription(): ?string
{
return 'An optional description'; // returning null omits the response description
}
public static function getExceptionSchema(): Schema|string
{
return (new \SwaggerBake\Lib\OpenApi\Schema())
->setTitle('MyException')
->setProperties([
(new SchemaProperty())->setType('string')->setName('code')->setExample('400'),
(new SchemaProperty())->setType('string')->setName('message')->setExample('error'),
(new SchemaProperty())->setType('string')->setName('wherever')->setExample('whatever you want')
]);
}
}
Extending Views and Controllers
It's possible to write extensions for SwaggerBake. Read the extensions documentation. There are several other options to extend functionality documented below:
Using Your Own SwaggerUI
You may use your own swagger or redoc install in lieu of the version that comes with SwaggerBake. Simply don't add a custom route as indicated in the installation steps. In this case just reference the generated swagger.json within your userland Swagger UI install.
Using Your Own Controller
You might want to perform some additional logic (checking for authentication) before rendering the built-in Swagger UI. This is easy to do. Just create your own route and controller, then reference the built-in layout and template:
// config/routes.php
$builder->connect('/my-swagger-docs', ['controller' => 'MySwagger', 'action' => 'index']);
To get started, copy SwaggerController into your project.
Note: SwaggerUiComponent has been deprecated in version 2.3.0 and will be removed in version 3.
Using Your Own Layout and Templates
You will need to use your own controller (see above). From there you can copy the layouts and templates into your project and inform your controller action to use them instead. Checkout out the CakePHP documentation on Views for specifics. This can be useful if you'd like to add additional functionality to SwaggerUI (or Redoc) using their APIs or if your project is not installed in your web servers document root (i.e. a sub-folder).
Multiple Instances of Swagger Bake
If your application has multiple APIs that are split into plugins you can generate unique OpenAPI schema, Swagger UI,
and Redoc for each plugin. Setup a new swagger_bake.php
and swagger.yaml
in plugins/OtherApi/config
. These
configurations should point to your plugins paths and namespaces. Next, create a custom
SwaggerController and load the configuration within initialize()
:
public function initialize(): void
{
parent::initialize();
Configure::load('OtherApi.swagger_bake', 'default', false); // note: `false` for the third argument is important
/*
* Only load the component if you are using a version older than v2.3.0. This component will be deprecated
* in v3.0.0
*/
$this->loadComponent('SwaggerBake.SwaggerUi');
}
When running bin/cake swagger bake
you will need to specify your plugins swagger_bake config:
bin/cake swagger bake --config OtherApi.swagger_bake
Debug Commands
In addition to swagger bake
these console helpers provide insight into how your Swagger documentation is generated.
swagger routes
Displays a list of routes that can be viewed in Swagger.
bin/cake swagger routes
swagger models
Displays a list of models that can be viewed in Swagger.
bin/cake swagger models
Bake Theme
SwaggerBake comes with Bake templates for scaffolding RESTful controllers compatible with SwaggerBake and OpenAPI 3.0 schema. Using the bake theme is completely optional, but will save you some time since the default bake theme is not specifically designed for RESTful APIs.
bin/cake bake controller {Name} --theme SwaggerBake
Common Issues
Swagger UI
No API definition provided.
Verify that swagger.json exists.
SwaggerBakeRunTimeExceptions
Unable to create swagger file. Try creating an empty file first or checking permissions
Create the swagger.json manually matching the path in your config/swagger_bake.php
file.
Output file is not writable
Change permissions on your swagger.json file
, 764
should do.
Controller not found
Make sure a controller actually exists for the route resource.
Missing routes
Make sure yours route are properly defined in config/routes.php
per the
CakePHP RESTful routing documentation.
Missing request or response samples
Sample schema is determined using CakePHP naming conventions. Does your controller name match your model names? For customizing response schema see OpenApiResponse.
Missing request schema
Sample schema is determined using CakePHP naming conventions. Does your controller name match your model names? For customizing request schema see OpenApiRequestBody.
Missing CSRF token body
Either disable CSRF protection on your main route in config/routes.php
or enable CSRF protection in Swagger
UI. The library does not currently support adding this in for you.
HTTP DELETE issues with Swagger UI
Swagger UI sends HTTP DELETE without an accept
header. If the record does not exist, an exception is generated.
This results in an HTML response being generated which can be quite large and cause the UI to be slow to render. To
get around this you can force an accept
value on the header using the CakePHP middleware:
# src/Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
->add(function(ServerRequestInterface $request, RequestHandlerInterface $handler){
$accept = $request->getHeader('accept');
if ($request->getMethod() === 'DELETE' && reset($accept) === '*/*') {
$request = $request->withHeader('accept', 'application/json');
}
return $handler->handle($request);
});
// other middleware...
return $middlewareQueue;
}
Read more about CakePHP middleware in the official documentation.
Contribute
Send pull requests to help improve this library. You can include SwaggerBake in your primary Cake project as a local source to make developing easier:
-
Make a fork of this repository and clone it to your localhost
-
Remove
cnizzardini\cakephp-swagger-bake
from yourcomposer.json
-
Add a paths repository to your
composer.json
"minimum-stability": "dev",
"repositories": [
{
"type": "path",
"url": "/absolute/local-path-to/cakephp-swagger-bake",
"options": {
"symlink": true
}
}
]
- Run
composer require cnizzardini/cakephp-swagger-bake @dev
Undo these steps when you're done. Read the full composer documentation on loading from path here: https://getcomposer.org/doc/05-repositories.md#path
Check out the extensions documentation to add functionality to this project.
Tests + Analysis
PHPUnit Test Suite:
composer test
PHPUnit, PHPCS, PHPSTAN, and PHPMD:
composer analyze
GrumPHP can be used to run tests and static analyzers in a pre-commit hook.
composer grumphp-init
I've set grumphp to be installed globally: https://github.com/phpro/grumphp/blob/master/doc/installation/global.md