Customizing API Platform OpenAPI Documentation
AI generated
SF
{ }
Symfony · API Platform · OpenAPI · PHP 8.4
Customizing API Platform OpenAPI Documentation
from auto generated to genuinely helpful

The automatically generated OpenAPI documentation of API Platform is a strong starting point, but without extra work it often stays too technical for external consumers. Custom summaries, concrete examples, and correctly documented security schemes turn the generic Swagger UI page into documentation that an outside team can actually work with without asking questions.

16 min read OpenApiFactory · Operation Attribute · Security Schemes API Platform 4 · Symfony 7 · PHP 8.4

1. Why generated OpenAPI documentation needs extra work

API Platform automatically generates a complete OpenAPI specification from the resource attributes, including schemas, status codes, and query parameters. For internal teams this automation is often already enough because they know the code and questions are quick. But as soon as external partners or a public API come into play, it quickly becomes clear that the generated OpenAPI documentation shows technical field names but provides no context on why a field exists or which values make sense in practice.

API Platform lets you document each operation deliberately without discarding the generated base entirely. Through the openapiContext argument on the operation attribute, you can maintain summary, description, examples, and even deprecation markers directly in the PHP class, so code and OpenAPI documentation can never drift apart because both come from the same source.

The second building block is the OpenApiFactory decorator, which lets you maintain global aspects such as the info block, server URLs, and security schemes centrally instead of repeating them in every single resource. Both mechanisms together allow OpenAPI documentation that stays both precise and maintainable.

2. Summaries and descriptions right on the attribute

The simplest way into better OpenAPI documentation is the openapi argument directly on the operation attribute. It accepts an Operation object from the OpenAPI namespace with summary and description, which appear prominently above the endpoint in Swagger UI. Instead of a generic description like Retrieves the collection of Order resources, it now shows a sentence that actually explains what the endpoint is used for in a business context.

These descriptions should never just repeat the technical operation, they should supply business context: which user group typically calls the endpoint, what side effects a call has, and what error cases are to be expected. This information is completely missing from OpenAPI documentation generated purely from reflection and has to be added by hand.


<?php

declare(strict_types=1);

namespace App\ApiResource;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;

/**
 * Documents the checkout operation with a meaningful summary
 * that goes beyond the auto generated default text.
 */
#[ApiResource(
    operations: [
        new Post(
            uriTemplate: '/orders/{id}/checkout',
            openapi: new OpenApiOperation(
                summary: 'Finalizes an order and triggers payment capture',
                description: 'Transitions the order into the "confirmed" state, '
                    . 'reserves stock and requests payment capture from the '
                    . 'configured payment provider. Idempotent per order id.',
            ),
        ),
    ],
)]
final class CheckoutOrder
{
    public string $id;
}

3. Custom examples for requests and responses

Concrete examples are the part of OpenAPI documentation with the greatest practical value, because developers are more likely to copy a working example than to read a schema line by line. API Platform allows you to attach custom examples blocks per operation through openapiContext, which appear in Swagger UI as a try it out template.

Realistic examples are especially important for fields with an ambiguous format, such as monetary amounts as an integer in the smallest unit or dates with a timezone suffix. A single correct example prevents more support requests here than an entire paragraph of prose, because developers recognize the format directly from the working value instead of having to interpret a description.


<?php

declare(strict_types=1);

namespace App\ApiResource;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;

/**
 * Adds a realistic request example showing the minor unit
 * amount format expected by the payment field.
 */
#[ApiResource(
    operations: [
        new Post(
            openapiContext: [
                'requestBody' => [
                    'content' => [
                        'application/json' => [
                            'example' => [
                                'amountMinorUnits' => 1999,
                                'currency' => 'EUR',
                                'reference' => 'ORDER-2026-000482',
                            ],
                        ],
                    ],
                ],
            ],
        ),
    ],
)]
final class Payment
{
    public int $amountMinorUnits;
    public string $currency;
}

4. The OpenApiFactory decorator for global customization

Some customizations do not affect a single operation but the entire document: contact information, license details, several server URLs for staging and production, or removing technical internal endpoints from the public OpenAPI documentation. For that you decorate OpenApiFactoryInterface and modify the fully built OpenApi object before it is delivered.

This decorator is also the right place to deliberately remove endpoints that need to exist but are not meant for external consumers from the public documentation, without technically disabling them. That keeps the OpenAPI documentation clean for partners while internal tools can keep working with the same endpoints.


<?php

declare(strict_types=1);

namespace App\OpenApi;

use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\OpenApi\Model\Contact;
use ApiPlatform\OpenApi\Model\Info;
use ApiPlatform\OpenApi\OpenApi;

/**
 * Decorates the generated OpenApi document with contact info
 * and removes internal only paths from the public spec.
 */
final readonly class InternalPathsOpenApiFactory implements OpenApiFactoryInterface
{
    public function __construct(
        private OpenApiFactoryInterface $decorated,
    ) {
    }

    public function __invoke(array $context = []): OpenApi
    {
        $openApi = $this->decorated->__invoke($context);

        $info = new Info(
            title: $openApi->getInfo()->getTitle(),
            version: $openApi->getInfo()->getVersion(),
            description: 'Public API for order management and checkout',
            contact: new Contact(name: 'API Support', email: 'api@mironsoft.de'),
        );

        $paths = $openApi->getPaths();
        $paths->removePath('/internal/health-check');

        return $openApi->withInfo($info)->withPaths($paths);
    }
}

5. Documenting security schemes correctly

A frequently overlooked part of OpenAPI documentation is the security schemes. When an API is secured with bearer tokens or OAuth2, the components.securitySchemes object must be properly maintained, otherwise Swagger UI cannot display an authorization dialog and external developers do not know how to authenticate. Through the OpenApiFactory decorator, a SecurityScheme object with type http, scheme bearer, and format JWT can be registered globally.

In addition, every operation that requires authentication should explicitly reference it in the security field instead of relying on an implicit global rule. That makes the OpenAPI documentation unambiguously readable at each individual endpoint, without a developer having to check elsewhere in the document whether and how an endpoint is protected.

6. Tags and grouping for large APIs

With APIs that have more than a dozen resources, the default Swagger UI view quickly becomes cluttered. API Platform supports the tags array per operation, which groups related endpoints into collapsible sections in Swagger UI, for example orders, payments, and shipping kept separate instead of one single long list.

Through the OpenApiFactory decorator, you can additionally define tag descriptions and a fixed order, so the most important resources appear at the top of the documentation for new developers instead of being scattered randomly in alphabetical order.

7. Documenting custom operations without CRUD semantics

Not every endpoint follows the classic CRUD pattern. An action like cancel order or export report can technically be modeled as a POST operation, but needs OpenAPI documentation that makes it clear this is not creating a new resource but triggering a state transition or a side effect. The openapi argument with a custom summary is mandatory here, because the automatic derivation from the resource name is usually misleading for such actions.

It is also worth explicitly adding the possible error responses to the responses block of the OpenAPI documentation for such action endpoints, for example a 409 conflict status code when an order was already cancelled. Without this addition, a client developer often only realizes this case is even possible after the first failure in production.

8. Maintaining documentation across multiple API versions

Once an API supports several active versions at the same time, the OpenAPI documentation also has to be delivered separately per version, so a client does not accidentally see fields from a newer version in the old documentation. The OpenApiFactory decorator can return different Info objects and even different sets of paths based on the version parameter passed in the context.

A deprecated flag directly on the affected operation is additionally mandatory as soon as an endpoint has been replaced in a newer version. Swagger UI visually highlights this marker and, ideally, the description immediately points to the successor endpoint, which significantly reduces migration effort for consumers.

9. Documentation approaches compared

The table below shows which mechanism is the right one for which kind of customization to OpenAPI documentation.

Customization Mechanism Scope When to use
Summary and description openapi argument on the attribute Single operation Always, for business context
Request examples openapiContext examples Single operation For ambiguous field formats
Info block, contact, servers OpenApiFactory decorator Entire document Maintain centrally once
Security schemes OpenApiFactory decorator Entire document For bearer or OAuth2 auth
Hiding internal paths OpenApiFactory decorator Entire document Separating public vs internal API

In practice, well documented API Platform projects combine both mechanisms: operation attributes for business context right at the code, and a single OpenApiFactory decorator for everything that affects the whole document. This split keeps the OpenAPI documentation consistent without needing changes in multiple places at once.

Mironsoft

Symfony and API Platform architecture for demanding APIs

OpenAPI documentation that partners can actually work with?

We rework your generated API Platform documentation with real examples, clear security schemes, and clean grouping, so external teams can integrate without asking questions.

Documentation audit

Reviewing the existing OpenAPI specification for gaps

OpenApiFactory setup

Central decorator configuration for security and branding

Partner onboarding

Preparing documentation for external API consumers

10. Summary

The automatically generated OpenAPI documentation of API Platform is a solid starting point, but it does not replace the manual maintenance of business context, concrete examples, and correctly documented security schemes. Through the openapi argument on the operation attribute, summary, description, and examples can be maintained directly in the code, while the OpenApiFactory decorator centrally controls global aspects such as the info block, security schemes, and internal paths.

Anyone who consistently uses both mechanisms ends up with OpenAPI documentation that is not only technically correct but genuinely helps external developers integrate an API without constant back and forth. Especially for public APIs with outside partner teams, this investment in documentation is directly measurable in the number of support requests.

OpenAPI documentation in API Platform: the essentials

Operation attributes

openapi argument for summary, description, and examples right on the resource class.

OpenApiFactory decorator

Central place for the info block, security schemes, and hiding internal paths.

Security schemes

SecurityScheme objects make bearer or OAuth2 auth directly testable in Swagger UI.

Tags and versioning

Grouping and deprecated markers keep large, multi version APIs organized.

11. FAQ: OpenAPI documentation in API Platform

1Change an endpoint's summary?
Through the openapi argument on the operation attribute with summary and description parameters.
2Add request examples?
Through openapiContext with a requestBody block and example array under the matching content type.
3What does OpenApiFactory do?
Decorates the generated OpenApi object for the info block, security schemes, or removing internal paths.
4Document bearer token?
With a SecurityScheme object of type http, scheme bearer, and format JWT in the OpenApiFactory decorator.
5Hide internal endpoints?
Yes, remove the path from the Paths object in the OpenApiFactory decorator, the endpoint stays technically reachable.
6Group endpoints?
Through the tags array per operation, complemented by tag descriptions in the OpenApiFactory decorator.
7Document action without CRUD?
With a custom summary and added error responses like 409 in the responses block of the OpenAPI documentation.
8Mark deprecated endpoint?
With the deprecated flag on the operation, visible in Swagger UI, description should point to the successor.
9Stays in sync automatically?
Yes, because it is maintained directly on the PHP class and cannot drift like separately maintained wiki pages.
10Document multiple API versions?
The OpenApiFactory decorator returns different Info objects and path sets based on the version parameter in the context.