# Schwager (*)
Note: This package is experimental, not stable.
The Schwager package provides an API spec generator for the Router package. The complementary package chevere/schwager-html (opens new window) enables to create an HTML representation for Schwager.
💡 Schwager introduction
Read Schwager API (opens new window) and Schwager HTML (opens new window) at Rodolfo's blog for a compressive introduction to this package.
# Installing
Schwager is available through Packagist (opens new window) and the repository source is at chevere/schwager (opens new window).
composer require chevere/schwager
# Specification
The Schwager API spec has the following general format:
{
    "api": "<API>",
    "name": "<NAME>",
    "version": "<VERSION>",
    "servers": [
        {
            "url": "<SERVER_URL>",
            "description": "<SERVER_DESCRIPTION>"
        }
    ],
    "paths": {
        "<PATH>": {
            "name": "<PATH_NAME>",
            "group": "<PATH_GROUP>",
            "regex": "<PATH_REGEX>",
            "variables": {
                "<VARIABLE>": {
                    "type": "string",
                    "description": "<VARIABLE_DESCRIPTION>",
                    "regex": "<VARIABLE_REGEX>"
                }
            },
            "endpoints": {
                "<METHOD>": {
                    "description": "<ENDPOINT_DESCRIPTION>",
                    "request" : {
                        "headers": {
                            <REQUEST_HEADERS>
                        },
                        "query": {
                            <REQUEST_QUERY_SCHEMA>
                        },
                        "body":  {
                            <REQUEST_BODY_SCHEMA>
                        },
                    },
                    "responses": {
                        "<STATUS_CODE>": [
                            {
                                "context": "<RESPONSE_CONTEXT>",
                                "headers": {
                                    <RESPONSE_HEADERS>
                                },
                                "body": {
                                    <RESPONSE_BODY_SCHEMA>
                                }
                            },
                        ]
                    }
                }
            }
        }
    }
}
# Identification
Properties for API identification.
<API><NAME><VERSION>
# Servers
The servers array indicate the server(s) available for interacting with the API.
<SERVER_URL><SERVER_DESCRIPTION>
# Paths
The paths property contains a map for URI paths.
<PATH>
For each path it takes the following properties:
<PATH_NAME><PATH_GROUP><PATH_REGEX>
# Variables
Path variables are mapped by name within the variables property.
<VARIABLE>
For each variable it provides the following properties. Path variables are always of type string.
<VARIABLE_DESCRIPTION><VARIABLE_REGEX>
# Endpoints
Path endpoints are mapped by HTTP method name within the endpoints property.
<METHOD><ENDPOINT_DESCRIPTION>
# Schemas
The body schema *_BODY_SCHEMA describes the payload body. It supports parameter schema of any type.
The query schema REQUEST_QUERY_SCHEMA describes the request query string. It supports an array of strings.
# Request
Request metadata is taken from the Request attribute
<REQUEST_HEADERS><REQUEST_QUERY_SCHEMA><REQUEST_BODY_SCHEMA>
# Responses
Endpoint responses are mapped by status code within the responses property. Response metadata is taken from the Response attribute
<STATUS_CODE>
Schwager supports multiple responses for the same status code. For each response it provides the following properties:
<RESPONSE_CONTEXT><RESPONSE_HEADERS><BODY_RESPONSE_SCHEMA>
# Creating API spec
To create an API spec pass an object implementing RouterInterface and a DocumentSchema. Optionally, you can provide one or more ServerSchema objects.
use Chevere\Schwager\DocumentSchema;
use Chevere\Schwager\ServerSchema;
use Chevere\Schwager\Spec;
use function Chevere\Router\router;
$router = router();
$document = new DocumentSchema(
    api: 'chevere',
    name: 'Chevere API',
    version: '1.0.0'
);
$server = new ServerSchema(
    url: 'https://localhost:8080',
    description: 'Development server'
);
$spec = new Spec($router, $document, $server);
Use method toArray to get the printer-ready array needed to export to other formats.
$array = $spec->toArray();
# Filtering result
The arrayFilter* functions provided by the Standard component enable to modify and/or filter the generated API spec. This is useful to remove null values, empty strings and context-aware redundant information.
For example to recursive filter the array by value $v and key $k:
use function Chevere\Standard\arrayFilterBoth;
$array = arrayFilterBoth($spec->toArray(), function ($v, $k) {
    return match (true) {
        $v === null => false,
        $v === [] => false,
        $v === '' => false,
        $k === 'required' && $v === true => false,
        $k === 'regex' && $v === '^.*$' => false,
        $k === 'body' && $v === [
            'type' => 'array#map',
        ] => false,
        default => true,
    };
});
The match used in the code above indicates that for every key value pair:
- Remove if the value is 
null - Remove if the value is 
[] - Remove if the value is empty string
 - Remove if the key is 
requiredand value istrue - Remove if the key is 
regexand value is^.*$ - Remove if the key is 
bodyand value is['type' => 'array#map'] - (default) Keep as is
 
For cases 1,2,3 the removal is for empty values while for cases 4,5,6 is because of redundant info.
# Export
Use the built-in Filesystem component to store the converted array with native json_encode (opens new window) as a JSON file.
use function Chevere\Filesystem\fileForPath;
$json = json_encode($array, JSON_PRETTY_PRINT);
$file = fileForPath(__DIR__ . '/api.json');
$file->put($json);
🪄 A PHP array can be converted to any format including YAML (opens new window), XML (opens new window) and more.