Slim 4 - API documentation with Swagger

Daniel Opitz
Daniel Opitz
12 Jun 2020

Table of contents

Requirements

Introduction

This article explains how to expose swagger-ui inside your Slim project through a route (eg. /docs), without the need for node.

Just add a reference to your swagger Yaml or JSON specification, and enjoy swagger-ui in all it’s glory.

Preview:

screely-1591996310595

Installation

To parse the OpenAPI Yaml file, we have to install a good Yaml parser:

composer require symfony/yaml

For demonstration purpose download this example file, or just use your own specification:

Save the yaml file in the resources/docs/ directory. If not exists, create it.

Template

Create a new template file: templates/docs/swagger.twig and copy/paste this content:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>API Specification - Swagger UI</title>
    <link rel="stylesheet" type="text/css"
          href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.26.1/swagger-ui.css">
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.26.1/swagger-ui-bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.26.1/swagger-ui-standalone-preset.js"></script>
<script>
    window.onload = function () {
        const ui = SwaggerUIBundle({
            spec: {{ spec|raw }},
            dom_id: '#swagger-ui',
            deepLinking: true,
            presets: [
                SwaggerUIBundle.presets.apis,
            ],
            plugins: [
                SwaggerUIBundle.plugins.DownloadUrl
            ],
        })
        window.ui = ui
    }
</script>
</body>
</html>

Route

Create a new action class: src/Action/Docs/SwaggerUiAction.php

<?php

namespace App\Action\Docs;

use App\Responder\Responder;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\Yaml\Yaml;

final class SwaggerUiAction
{
    /**
     * @var Responder
     */
    private $responder;

    /**
     * The constructor.
     *
     * @param Responder $responder The responder
     */
    public function __construct(Responder $responder)
    {
        $this->responder = $responder;
    }

    /**
     * Action.
     *
     * @param ServerRequestInterface $request The request
     * @param ResponseInterface $response The response
     *
     * @return ResponseInterface The response
     */
    public function __invoke(
        ServerRequestInterface $request, 
        ResponseInterface $response
    ): ResponseInterface {
        // Path to the yaml file
        $yamlFile = __DIR__ . '/../../../resources/docs/petstore.yaml';

        $viewData = [
            'spec' =>json_encode(Yaml::parseFile($yamlFile)),
        ];

        return $this->responder->render($response, 'docs/swagger.twig', $viewData);
    }
}

Add a new route:

$app->get('/docs/v1', \App\Action\Docs\SwaggerUiAction::class);

Then navigate to http://localhost/docs/v1 and you should see a pretty Swagger UI documentation.