A delightfully tasty tool for generating Swagger documentation with OpenApi 3.0.0 schema. This plugin automatically builds your Swagger UI and ReDoc from your existing cake models and routes.
- Creates OpenApi paths and operations from your RESTful routes and controllers.
- Creates OpenAPI Schema from your Entities and Tables.
- Integrates with: Paginator, friendsofcake/search, Authentication, Validator, and Bake.
- Provides additional functionality through Annotations and Doc Blocks.
Demo Site | Demo Code | Screenshot | Console Demo
- Installation
- Setup
- Automatic Documentation
- Doc Blocks
- Annotations for Extended Functionality
- Extending SwaggerBake
- Console Commands
- Bake Theme
- ...
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.
Run bin/cake swagger install
Then just add a route.
-
Create a base swagger.yml file in
config\swagger.yml
. An example file is provided here. -
Create a
config/swagger_bake.php
file. See the example file here for further explanation. -
Create a route for the SwaggerUI page in
config/routes.php
.
Create a route for the SwaggerUI page in config/routes.php
, example:
$builder->connect('/my-swagger-ui', ['controller' => 'Swagger', 'action' => 'index', 'plugin' => 'SwaggerBake']);
If Hot Reload is enabled (see config) then you should be able to browse to the above
route. Otherwise you must first run bin/cake swagger bake
to generate your swagger documentation.
I built this library to reduce the need for annotations to build documentation. SwaggerBake will automatically build the following from your existing routes and models without additional effort:
- Paths
- Resource (route)
- Operations
- Summary and description
- GET, POST, PATCH, DELETE
- Form fields and JSON using your Cake models
- Responses
- Sub resources
- Security/Authentication
- Schema
See details for how CakePHP conventions are interpreted into OpenAPI 3.0 schema.
SwaggerBake works with your existing YML definitions and will not overwrite anything. By default, it uses
components > schemas > Exception as your Swagger documentations Exception schema. See the default
swagger.yml and exceptionSchema
in swagger_bake.php for more info.
SwaggerBake will parse your DocBlocks for information. The
first line reads as the Operation Summary and the second as the Operation Description, @see
, @deprecated
, and
@throws
are also supported. Throw tags use the Exception classes HTTP status code. For instance, a
MethodNotAllowedException
displays as a 405 response in Swagger UI, while a standard PHP Exception displays as a 500
code.
/**
* Swagger Operation Summary
*
* This displays as the operations long description
*
* @see https://book.cakephp.org/4/en/index.html The link and this description appear in Swagger
* @deprecated
* @throws BadRequestException
* @throws Exception
*/
public function index() {}
SwaggerBake provides some optional Annotations for enhanced functionality. These can be imported individually from
SwaggerBake\Lib\Annotation
or set to an alias such as Swag
: use SwaggerBake\Lib\Annotation as Swag
.
Method level annotation for adding CakePHP Paginator query parameters: page, limit, sort, and direction.
use SwaggerBake\Lib\Annotation as Swag;
/**
* @Swag\SwagPaginator
*/
public function index() {
$employees = $this->paginate($this->Employees);
$this->set(compact('employees'));
$this->viewBuilder()->setOption('serialize', ['employees']);
}
Method level annotation for documenting search parameters using the popular
friendsofcake/search plugin. Note, you must import @SwagSearch
from a
different namespace.
use SwaggerBake\Lib\Extension\CakeSearch\Annotation\SwagSearch;
/**
* @SwagSearch(tableClass="\App\Model\Table\ActorsTable", collection="default")
*/
public function index() {}
Method level annotation for adding query parameters. Read the comments to see all supported OpenAPI properties.
/**
* @Swag\SwagQuery(name="queryParamName", type="string", description="string")
*/
public function index() {}
Method level annotation for adding form data fields. Read the comments to see all supported OpenAPI properties.
/**
* @Swag\SwagForm(name="fieldName", type="string", description="string", required=false, enum={"a","b"})
*/
public function index() {}
Method level annotation for building query or form parameters from a DataTransferObject. DTOs are more than just a best practice. Using them with SwaggerBake greatly reduces the amount of annotations you need to write. Consider using a DTO in place of SwagQuery or SwagForm. SwagDto uses either SwagDtoProperty or your existing Doc Blocks to build swagger query and post parameters.
/**
* @Swag\SwagDto(class="\App\Dto\ActorDto")
*/
public function index() {}
Example DTO:
namespace App\Dto;
class ActorDto {
/**
* Last name required
* @var string
* @required
*/
private $lastName;
/** @var string */
private $firstName;
Property level annotation for use in your SwagDto classes. Read the comments to see all supported properties.
class ActorDto {
/**
* @SwagDtoQuery(name="firstName", type="string", required=true)
*/
private $firstName;
/**
* @SwagDtoQuery(name="gender", type="string", enum="{"male","female","other"}")
*/
private $gender;
Property level annotation for use in your SwagDto classes. Read the comments to see all supported properties.
class ActorDto {
/**
* @SwagDtoForm(name="title", type="string", required=true)
*/
private $title;
/**
* @SwagDtoForm(name="age", type="integer", format="int32")
*/
private $age;
Method level annotation for adding header parameters. Read the comments to see all supported OpenAPI properties.
/**
* @Swag\SwagHeader(name="X-HEAD-ATTRIBUTE", type="string", description="string")
*/
public function index() {}
Method level annotation for adding authentication requirements. This annotation takes precedence over settings that SwaggerBake gathers from AuthenticationComponent. Read details below.
/**
* @Swag\SwagSecurity(name="BearerAuth", scopes={"Read","Write"})
*/
public function index() {}
Method level annotation for OpenApi Operations. Toggle visibility with isVisible and customize tag names which default to the controllers name.
/**
* @SwagOperation(isVisible=false, tagNames={"MyTag","AnotherTag"})
*/
public function index() {}
Method level annotation for describing request body. Set ignoreCakeSchema for full control over request body.
/**
* @Swag\SwagRequestBody(description="my description", required=true, ignoreCakeSchema=true)
*/
public function index() {}
Method level annotation for describing custom content in request body.
/**
* @Swag\SwagRequestBodyContent(refEntity="#/components/schemas/Actor", mimeType="application/json")
*/
public function index() {}
Method level annotation for defining custom response schema. Leave refEntity empty to define no schema. Note, as of
v1.3
, please use statusCode
instead of httpCode
as it will be removed in a future version. See 1.3 release notes.
/**
* @Swag\SwagResponseSchema(refEntity="#/components/schemas/Actor", description="summary", statusCode="200")
* @Swag\SwagResponseSchema(refEntity="", description="Support range status codes", statusCode="5XX")
* @Swag\SwagResponseSchema(refEntity="#/components/schemas/Actor", mimeType="application/xml")
* @Swag\SwagResponseSchema(refEntity="#/components/schemas/Actor", mimeType="application/json")
*/
public function index() {}
Class level annotation for exposing controllers to Swagger UI. You can hide entire controllers with this annotation.
/**
* @Swag\SwagPath(isVisible=false, description="optional description", summary="operational summary")
*/
class UsersController extends AppController {
Class level annotation for exposing entities to Swagger UI. By default, all entities with routes will display as Swagger schema. You can hide a schema or display a schema that does not have an associated route.
/**
* @Swag\SwagEntity(isVisible=false, title="optional title", description="optional description")
*/
class Employee extends Entity {
Class level annotation for customizing Schema Attributes. Read the comments to see all supported OpenAPI properties.
/**
* @Swag\SwagEntityAttribute(name="modified", type="string", description="string")
*/
class Employee extends Entity {
There are several options to extend functionality.
You may use your own swagger 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.
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']);
Use SwaggerController as your base.
There a three options for generating swagger.json:
-
Call
swagger bake
which can be included as part of your build process. -
Enable the
hotReload
option in config/swagger_bake.php (recommended for local development only). -
Call SwaggerBake programmatically:
$swagger = (new \SwaggerBake\Lib\Factory\SwaggerFactory())->create();
$swagger->toArray(); # returns swagger array
$swagger->toString(); # returns swagger json
$swagger->writeFile('/full/path/to/your/swagger.json'); # writes swagger.json
In addition to swagger bake
these console helpers provide insight into how your Swagger documentation is generated.
Displays a list of routes that can be viewed in Swagger.
bin/cake swagger routes
Displays a list of models that can be viewed in Swagger.
bin/cake swagger models
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
OpenAPI Schema Support Roadmap
- Swagger uses your existing swagger.yml as a base for adding additional paths and schema.
- Generates JSON based on the OpenAPI 3 specification. I am still working on implementing the full spec.
- All Schemas and Paths generated must have the following in your CakePHP Application:
- App\Model\Entity class (for schemas only)
- App\Controller class
- Must be a valid route
- Entity Attributes:
- Hidden attributes will not be visible
- Primary Keys will be set to read only by default.
- DateTime fields named
created
andmodified
are automatically set to read only per Cake convention.
- CRUD Responses
- Index, Edit, Add, and View methods default to an HTTP 200 with the Controllers related Cake Entity schema.
- Delete defaults to HTTP 204 (no content).
- Table Validators:
- Reads in Validator rules such as requirePresence, minLength, maxLength, basic math comparison operators, regex, inList, hasAtLeast, and hasAtMost.
- Security Scheme
- Leverages the CakePHP AuthenticationComponent
- Will automatically set security on operations if a single securityScheme
is defined in your swagger.yaml. If more than one security schema exists you will need to use
@SwagSecurity
. @SwagSecurity
takes precedence.
- SwaggerBake has been developed primarily for application/json and application/x-www-form-urlencoded, but does have some support for application/xml and should work with application/vnd.api+json.
SwaggerBake does not document schema associations. If your application includes associations on things like
GET requests, you can easily add them into your swagger documentation through the OpenAPI allOf
property. Since
SwaggerBake works in conjunction with OpenAPI YAML you can easily add a new schema with this association. Below is an
example of extending an existing City schema to include a Country association.
# in your swagger.yml
components:
schemas:
CityExtended:
description: 'City with extended information including Country'
type: object
allOf:
- $ref: '#/components/schemas/City'
- type: object
properties:
country:
$ref: '#/components/schemas/Country'
Then in your controller action you'd specify the Schema:
/**
* View method
* @Swag\SwagResponseSchema(refEntity="#/components/schemas/CityExtended")
*/
public function view($id)
{
$this->request->allowMethod('get');
$city = $this->Cities->get($id, ['contain' => ['Countries']]);
$this->set(compact('cities'));
$this->viewBuilder()->setOption('serialize', 'cities');
}
The demo application includes this and many other examples of usage. Read more about oneOf
, anyOf
, allOf
, and
not
in the OpenAPI 3 documentation.
This is built for CakePHP 4.x only. A cake-3.8 option is available, but not supported.
Version | Cake Version | Supported | Unit Tests | Notes |
---|---|---|---|---|
1.* | 4.* | Yes | Yes | Currently supported |
cake-3.8 | 3.8.* | No | Yes | See branch cake-3.8. Completely untested and unsupported |
No API definition provided.
Verify that swagger.json exists.
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.
By default Cake RESTful resources will only create routes for index, view, add, edit and delete. You can add and remove paths using CakePHPs route resource functionality. Read the Cake Routing documentation which describes in detail how to add, remove, modify, and alter routes.
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.
Make sure the route is properly defined in your config/routes.php
file.
This is a new library so please take some steps before reporting issues. You can copy & paste the JSON SwaggerBake outputs into https://editor.swagger.io/ which will automatically convert the JSON into YML and display potential schema issues.
Please included the following in your issues a long with a brief description:
- Steps to Reproduce
- Actual Outcome
- Expected Outcome
Feature requests are welcomed.
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 clone of this repository
-
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
vendor/bin/phpunit