Skip to content

A CakePHP Swagger Generator. Automatically generate Swagger documentation from your existing routes with minimal comments and configuration

License

Notifications You must be signed in to change notification settings

bmudda/cakephp-swagger-bake

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SwaggerBake plugin for CakePHP4

Latest Version on Packagist Build Status License: MIT

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.

Demo Site | Demo Code | Screenshot | Console Demo

Table of Contents

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');
}

Setup

For standard applications that have not split their API into plugins, the automated setup should work. Otherwise use the manual setup.

Automated Setup

Run bin/cake swagger install

Then just add a route.

Manual Setup

  • 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.

Last Step

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.

Automatic 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.

Doc Blocks

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() {}

Annotations for Extended Functionality

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.

@SwagPaginator

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']);
}

@SwagSearch

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() {}

@SwagQuery

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() {}

@SwagForm

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() {}

@SwagDto

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;

@SwagDtoQuery

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;

@SwagDtoForm

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;

@SwagHeader

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() {}

@SwagSecurity

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() {}

@SwagOperation

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() {}

@SwagRequestBody

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() {}

@SwagRequestBodyContent

Method level annotation for describing custom content in request body.

/**
 * @Swag\SwagRequestBodyContent(refEntity="#/components/schemas/Actor", mimeType="application/json")
 */
public function index() {}

@SwagResponseSchema

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() {}

@SwagPath

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 {

@SwagEntity

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 {

@SwagEntityAttribute

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 {

Extending SwaggerBake

There are several options to extend functionality.

Using Your Own SwaggerUI

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.

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']);

Use SwaggerController as your base.

Generate Swagger On Your Terms

There a three options for generating swagger.json:

  1. Call swagger bake which can be included as part of your build process.

  2. Enable the hotReload option in config/swagger_bake.php (recommended for local development only).

  3. 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

Console 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

Details

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 and modified 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.

Supported Versions

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

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.

Other Issues

Missing actions (missing paths) in Swagger

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.

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.

My route isn't displaying in Swagger UI

Make sure the route is properly defined in your config/routes.php file.

Reporting Issues

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.

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 clone of this repository

  • Remove cnizzardini\cakephp-swagger-bake from your composer.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

Unit Tests

vendor/bin/phpunit

About

A CakePHP Swagger Generator. Automatically generate Swagger documentation from your existing routes with minimal comments and configuration

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • PHP 96.8%
  • HTML 3.2%