API Platform natively support the OpenAPI API specification format.

The specification of the API is available at the /docs.json path.
By default, OpenAPI v3 is used.
You can also get an OpenAPI v3-compliant version thanks to the spec_version query parameter: /docs.json?spec_version=3
It also integrates a customized version of Swagger UI and ReDoc, some nice tools to display the API documentation in a user friendly way.
You can also dump an OpenAPI specification for your API.
OpenAPI, JSON format:
docker-compose exec php \
    bin/console api:openapi:export
OpenAPI, YAML format:
docker-compose exec php \
    bin/console api:openapi:export --yaml
Create a file containing the specification:
docker-compose exec php \
    bin/console api:openapi:export --output=swagger_docs.json
If you want to use the old OpenAPI v2 (Swagger) JSON format, use:
docker-compose exec php \
    bin/console api:swagger:export
Symfony allows to decorate services, here we
need to decorate api_platform.openapi.factory.
In the following example, we will see how to override the title of the Swagger documentation and add a custom filter for
the GET operation of /foos path.
# api/config/services.yaml
    App\OpenApi\OpenApiFactory:
        decorates: 'api_platform.openapi.factory'
        arguments: [ '@App\OpenApi\OpenApiFactory.inner' ]
        autoconfigure: false<?php
namespace App\OpenApi;
use ApiPlatform\Core\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\Core\OpenApi\OpenApi;
use ApiPlatform\Core\OpenApi\Model;
class OpenApiFactory implements OpenApiFactoryInterface
{
    private $decorated;
    public function __construct(OpenApiFactoryInterface $decorated)
    {
        $this->decorated = $decorated;
    }
    public function __invoke(array $context = []): OpenApi
    {
        $openApi = $this->decorated->__invoke($context);
        $pathItem = $openApi->getPaths()->getPath('/api/grumpy_pizzas/{id}');
        $operation = $pathItem->getGet();
        $openApi->getPaths()->addPath('/api/grumpy_pizzas/{id}', $pathItem->withGet(
            $operation->withParameters(array_merge(
                $operation->getParameters(),
                [new Model\Parameter('fields', 'query', 'Fields to remove of the output')]
            ))
        ));
        $openApi = $openApi->withInfo((new Model\Info('New Title', 'v2', 'Description of my custom API'))->withExtensionProperty('info-key', 'Info value'));
        $openApi = $openApi->withExtensionProperty('key', 'Custom x-key value');
        $openApi = $openApi->withExtensionProperty('x-value', 'Custom x-value value');
        return $openApi;
    }
}The impact on the swagger-ui is the following:

Sometimes you may want to change the information included in your OpenAPI documentation. The following configuration will give you total control over your OpenAPI definitions:
<?php
// api/src/Entity/Product.php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
#[ApiResource]
class Product // The class name will be used to name exposed resources
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    private ?int $id = null;
    /**
     * @param string $name A name property - this description will be available in the API documentation too.
     *
     */
    #[ORM\Column]
    #[Assert\NotBlank]
    #[ApiProperty(
        attributes: [
            "openapi_context" => [
                "type" => "string",
                "enum" => ["one", "two"],
                "example" => "one",
            ],
        ],
    )]
    public string $name;
    #[ORM\Column(type: "datetime")] 
    #[Assert\DateTime]
    #[ApiProperty(
        openapi_context: ["type" => "string", "format" => "date-time"]
    )]
    public $timestamp;
    // ...
}# api/config/api_platform/resources.yaml
resources:
    App\Entity\Product:
      properties:
        name:
          attributes:
            openapi_context:
              type: string
              enum: ['one', 'two']
              example: one
        timestamp:
          attributes:
            openapi_context:
              type: string
              format: date-time<?xml version="1.0" encoding="UTF-8" ?>
<resources xmlns="https://api-platform.com/schema/metadata"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="https://api-platform.com/schema/metadata https://api-platform.com/schema/metadata/metadata-2.0.xsd">
    <resource class="App\Entity\Product">
        <property name="name">
            <attribute name="openapi_context">
                <attribute name="type">type</attribute>
                <attribute name="enum">
                    <attribute>one</attribute>
                    <attribute>two</attribute>
                </attribute>
                <attribute name="example">one</attribute>
            </attribute>
        </property>
        <property name="timestamp">
            <attribute name="openapi_context">
                <attribute name="type">string</attribute>
                <attribute name="format">date-time</attribute>
            </attribute>
        </property>
    </resource>
</resources>This will produce the following Swagger documentation:
"components": {
    "schemas": {
        "GrumpyPizza:jsonld": {
            "type": "object",
            "description": "",
            "properties": {
                "@context": {
                    "readOnly": true,
                    "type": "string"
                },
                "@id": {
                    "readOnly": true,
                    "type": "string"
                },
                "@type": {
                    "readOnly": true,
                    "type": "string"
                },
                "timestamp": {
                    "type": "string",
                    "format": "date-time"
                },
                "id": {
                    "readOnly": true,
                    "type": "integer"
                },
                "name": {
                    "type": "string",
                    "enum": [
                        "one",
                        "two"
                    ],
                    "example": "one"
                }
            }
        }
    }
}To pass a context to the OpenAPI v2 generator, use the swagger_context attribute (notice the prefix: swagger_ instead of openapi_).
API Platform generates a definition name based on the serializer groups defined
in the (de)normalization_context. It’s possible to override the name
thanks to the swagger_definition_name option:
#[ApiResource(
    collectionOperations: [
        "post" => [
            "denormalization_context" => [
                "groups" => ["user:read"],
                "swagger_definition_name" => "Read",
            ],
        ],
    ],
)]
class User
{
}It’s also possible to re-use the (de)normalization_context:
#[ApiResource(
    collectionOperations: [
        "post" => [
            "denormalization_context" => User::API_WRITE,
        ],
    ],
)]
class User
{
    const API_WRITE = [
        'groups' => ['user:read'],
        'swagger_definition_name' => 'Read',
    ];
}You also have full control over both built-in and custom operations documentation.
<?php
// api/src/Entity/Rabbit.php
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Controller\RandomRabbit;
#[ApiResource(collectionOperations: [
        'create_rabbit' => [
            'method'          => 'post',
            'path'            => '/rabbit/create',
            'controller'      => RandomRabbit::class,
            'openapi_context' => [
                'summary'     => 'Create a rabbit picture',
                'description' => "# Pop a great rabbit picture by color!\n\n",
                'requestBody' => [
                    'content' => [
                        'application/json' => [
                            'schema'  => [
                                'type'       => 'object',
                                'properties' =>
                                    [
                                        'name'        => ['type' => 'string'],
                                        'description' => ['type' => 'string'],
                                    ],
                            ],
                            'example' => [
                                'name'        => 'Mr. Rabbit',
                                'description' => 'Pink Rabbit',
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ]
)]
class Rabbit
{}resources:
  App\Entity\Rabbit:
    collectionOperations:
      create_rabbit:
        method: post
        path: '/rabbit/create'
        controller: App\Controller\RandomRabbit
        openapi_context:
          summary: Random rabbit picture
          description: >
            # Pop a great rabbit picture by color!
                        
          requestBody:
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    name: { type: string }
                    description: { type: string }
                example:
                  name: Mr. Rabbit
                  description: Pink rabbit<?xml version="1.0" encoding="UTF-8" ?>
<resources xmlns="https://api-platform.com/schema/metadata"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="https://api-platform.com/schema/metadata
        https://api-platform.com/schema/metadata/metadata-2.0.xsd">
    <resource class="App\Entity\Rabbit">
        <collectionOperations>
            <collectionOperation name="create_rabbit">
                <attribute name="path">/rabbit/create</attribute>
                <attribute name="method">post</attribute>
                <attribute name="controller">App\Controller\RandomRabbit</attribute>
                <attribute name="openapi_context">
                    <attribute name="summary">Create a rabbit picture </attribute>
                    <attribute name="description"># Pop a great rabbit picture by color!!
</attribute>
                    <attribute name="content">
                        <attribute name="application/json">
                            <attribute name="schema">
                                <attribute name="type">object</attribute>
                                <attribute name="properties">
                                    <attribute name="name">
                                        <attribute name="type">string</attribute>
                                    </attribute>
                                    <attribute name="description">
                                        <attribute name="type">string</attribute>
                                    </attribute>
                                </attribute>
                            </attribute>
                        </attribute>
                    </attribute>
                </attribute>
            </collectionOperation>
        </collectionOperations>
    </resource>
</resources>
Sometimes you may want to have the API at one location, and the Swagger UI at a different location. This can be done by disabling the Swagger UI from the API Platform configuration file and manually adding the Swagger UI controller.
# api/config/packages/api_platform.yaml
api_platform:
    # ...
    enable_swagger_ui: false
    enable_re_doc: false# app/config/routes.yaml
swagger_ui:
    path: /docs
    controller: api_platform.swagger.action.uiChange /docs to the URI you wish Swagger to be accessible on.
Sometimes you may want to use a different Asset Package for the Swagger UI. In this way you’ll have more fine-grained control over the asset URL generations. This is useful i.e. if you want to use different base path, base URL or asset versioning strategy.
Specify a custom asset package name:
# config/packages/api_platform.yaml
api_platform:
    asset_package: 'api_platform'Set or override asset properties per package:
# config/packages/framework.yaml
framework:
    # ...
    assets:
        base_path: '/custom_base_path' # the default
        packages:
            api_platform:
                base_path: '/'As described in the Symfony documentation, it’s possible to override the Twig template that loads Swagger UI and renders the documentation:
{# templates/bundles/ApiPlatformBundle/SwaggerUi/index.html.twig #}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{% if title %}{{ title }} {% endif %}My custom template</title>
    {# ... #}
</html>You may want to copy the one shipped with API Platform and customize it.
AWS API Gateway supports OpenAPI partially, but it requires some changes. API Platform provides a way to be compatible with Amazon API Gateway.
To enable API Gateway compatibility on your OpenAPI docs, add api_gateway=true as query parameter: http://www.example.com/docs.json?api_gateway=true.
The flag --api-gateway is also available through the command-line.
If you implemented OAuth on your API, you should configure OpenApi’s authorization using API Platform’s configuration:
api_platform:
    oauth:
        # To enable or disable oauth.
        enabled: false
        # The oauth client id.
        clientId: ''
        # The oauth client secret.
        clientSecret: ''
        # The oauth type.
        type: 'oauth2'
        # The oauth flow grant type.
        flow: 'application'
        # The oauth token url.
        tokenUrl: '/oauth/v2/token'
        # The oauth authentication url.
        authorizationUrl: '/oauth/v2/auth'
        # The oauth scopes.
        scopes: []Note that clientId and clientSecret are being used by the SwaggerUI if enabled.
The info object provides metadata about the API like licensing information or a contact. You can specify this information using API Platform’s configuration:
api_platform:
    # The title of the API.
    title: 'API title'
    # The description of the API.
    description: 'API description'
    # The version of the API.
    version: '0.0.0'
    openapi:
        # The contact information for the exposed API.
        contact:
            # The identifying name of the contact person/organization.
            name:
            # The URL pointing to the contact information. MUST be in the format of a URL.
            url:
            # The email address of the contact person/organization. MUST be in the format of an email address.
            email:
        # A URL to the Terms of Service for the API. MUST be in the format of a URL.
        termsOfService:
        # The license information for the exposed API.
        license:
            # The license name used for the API.
            name:
            # URL to the license used for the API. MUST be in the format of a URL.
            url:You can also help us improve the documentation of this page.
Made with love by
Les-Tilleuls.coop can help you design and develop your APIs and web projects, and train your teams in API Platform, Symfony, Next.js, Kubernetes and a wide range of other technologies.
Learn more