Skip to content

OpenAPI ​

OpenApiHandler is a normal handler that returns an OpenAPI 3.0 document of all endpoints with the same version as its own. Register it like any endpoint.

Open the diagram at full size
yaml
application:
	mapping:
		Api: Tomaj\NetteApi\Presenters\*Presenter
		*: App\UI\*\**Presenter

latte:
	extensions:
		# the {apiLink} tag
		- Tomaj\NetteApi\Link\ApiLinkExtension

parameters:
	apiTokens:
		secret-token: '*'

services:
	router: App\RouterFactory::create
	apiPresenter:
		factory: Tomaj\NetteApi\Presenters\ApiPresenter
	- App\UI\Console\ConsolePresenter
	- Tomaj\NetteApi\Output\Configurator\EnvConfigurator
	- Tomaj\NetteApi\Error\DefaultErrorHandler
	- Tomaj\NetteApi\Misc\IpDetector

	apiLink: Tomaj\NetteApi\Link\ApiLink
	# {apiLink} calls the filter of this name
	latte.latteFactory:
		setup:
			- addFilter(apiLink, [@apiLink, link])

	- App\Api\BookListHandler
	- App\Api\BookCreateHandler
	# the listing handlers need ApiDecider, so they are registered by class name below
	# and created only when their endpoint is called
	- Tomaj\NetteApi\Handlers\OpenApiHandler(initData: [info: [title: 'Bookshelf API', description: 'Example API documented with OpenAPI']])
	- Tomaj\NetteApi\Handlers\ApiListingHandler

	apiDecider:
		factory: Tomaj\NetteApi\ApiDecider
		setup:
			- addApi(Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'books'), App\Api\BookListHandler, Tomaj\NetteApi\Authorization\NoAuthorization())
			- addApi(Tomaj\NetteApi\EndpointIdentifier('POST', 1, 'books'), App\Api\BookCreateHandler, Tomaj\NetteApi\Authorization\BearerTokenAuthorization(Tomaj\NetteApi\Misc\StaticTokenRepository(%apiTokens%)))
			# GET /api/v1/openapi, ?format=yaml with symfony/yaml installed
			- addApi(Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'openapi'), Tomaj\NetteApi\Handlers\OpenApiHandler, Tomaj\NetteApi\Authorization\NoAuthorization())
			# GET /api/v1/endpoints, a short JSON list of the version 1 endpoints
			- addApi(Tomaj\NetteApi\EndpointIdentifier('GET', 1, 'endpoints'), Tomaj\NetteApi\Handlers\ApiListingHandler, Tomaj\NetteApi\Authorization\NoAuthorization())

OpenApiHandler needs ApiDecider, which in turn holds the handlers, so register it by class name in addApi(). It is created only when its endpoint is called.

What goes into the document ​

FromInto
summary(), description(), tags(), deprecated()the operation
params()parameters, and requestBody for body params such as JSON and raw input
outputs()responses with JSON schemas
the authorization classsecuritySchemes and security: Bearer, Basic, or apiKey in query, header or cookie
params, the authorization400 when there are params, 401 unless NoAuthorization, and 500 always

Endpoints with your own authorization class appear without security.

Constructor ​

php
new OpenApiHandler(
    ApiDecider $apiDecider,
    ApiLink $apiLink,
    Nette\Http\Request $request,
    array $initData = [],        // merged into the document, e.g. info.title
    array $allowedEndpoints = [], // path pattern => methods to include; empty means all
    ?SpecBuilderInterface $specBuilder = null // custom builder, see below
)

?format=yaml returns YAML when symfony/yaml is installed; otherwise only json is allowed.

allowedEndpoints ​

Keys (or values in a list) are patterns matched case-insensitively against the endpoint path without version (e.g. users/list); values limit HTTP methods, e.g. ['users' => ['get', 'post'], 'orders/list' => 'get'].

WARNING

A pattern matches anywhere in the path, so users also includes admin/users-internal, and * is not a wildcard. Use patterns that are unique enough and check the generated document when it is public. See #211.

Builders ​

The document is created by small builders in Tomaj\NetteApi\OpenApi, each responsible for one part:

ClassCreates
SpecBuilderwhole document: info, servers, components, paths (filters APIs by version)
PathBuilderpaths and operations (summary, tags, parameters, request body, security, responses)
ParameterBuilderquery and cookie parameters
RequestBodyBuilderJSON, raw, form and multipart request bodies
ResponseBuildererror responses and their schemas, responses from handler outputs
SecuritySchemeBuildersecurity schemes and requirements from authorizations (override createScheme())

SchemaRegistry (transforms JSON schemas and collects definitions into components/schemas) and EndpointFilter (allowedEndpoints) are helpers created for each generated document.

Replacing a builder via DI ​

Extend the builder and register it in DI together with PathBuilder and SpecBuilder. OpenApiHandler gets SpecBuilder autowired, otherwise the default builders are used. Links are always created by the ApiLink of the handler.

Since 4.0 each builder has an interface (SpecBuilderInterface, PathBuilderInterface, ParameterBuilderInterface, RequestBodyBuilderInterface, ResponseBuilderInterface, SecuritySchemeBuilderInterface) and constructors accept the interface, so you can also replace a builder with your own implementation instead of extending it.

php
use Tomaj\NetteApi\Handlers\ApiHandlerInterface;
use Tomaj\NetteApi\OpenApi\ParameterBuilder;

class MyParameterBuilder extends ParameterBuilder
{
    public function build(ApiHandlerInterface $handler): array
    {
        $parameters = parent::build($handler);
        $parameters[] = ['name' => 'X-Request-Id', 'in' => 'header', 'required' => false, 'schema' => ['type' => 'string']];
        return $parameters;
    }
}
neon
services:
	- MyParameterBuilder
	- Tomaj\NetteApi\OpenApi\PathBuilder
	- Tomaj\NetteApi\OpenApi\SpecBuilder

FAQ ​

How do I change the title "Nette API"? ​

Pass initData: [info: [title: 'My API']]. It is merged recursively over the generated document.

Can I hide internal endpoints? ​

Yes, list the public ones in allowedEndpoints (mind the matching rules), or register a second OpenApiHandler for a different version.

Why are endpoints of version 2 missing? ​

The document covers only the version of the OpenApiHandler endpoint. Register one per version; see Links and versions.

Can I use the document with Swagger UI? ​

Yes, point Swagger UI at the URL of the endpoint. The library also has its own web console.

Is the OpenAPI endpoint public? ​

Only if you register it with NoAuthorization, as the OpenAPI example does. Any authorization works.

Released under the MIT License.