How to hide a route from API Platform documentation
Asked Answered
K

4

7

I'm building an API with API Platform under Symfony4,

I want to hide an entity in the doc which is accessible only to the ROLE_ADMIN of the blow no interest to be visible in the doc.

Here is the entity I want to hide:

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ApiResource(
 *     attributes={"access_control"="is_granted('ROLE_ADMIN')"}
 * )
 * @ORM\Entity(repositoryClass="App\Repository\OrderStatusRepository")
 */
class OrderStatus
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups("orderGET")
     */
    private $label;

    /**
     * @return int|null
     */
    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * @return null|string
     */
    public function getLabel(): ?string
    {
        return $this->label;
    }

    /**
     * @param string $label
     * @return OrderStatus
     */
    public function setLabel(string $label): self
    {
        $this->label = $label;

        return $this;
    }
}

Thank you for your help

Kamakura answered 9/1, 2019 at 13:49 Comment(0)
D
11

Symfony allows to decorate services, here we need to decorate api_platform.openapi.factory

Create src/OpenApi/OpenApiFactory.php with the following:

<?php

namespace App\OpenApi;

use ApiPlatform\Core\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\Core\OpenApi\Model\PathItem;
use ApiPlatform\Core\OpenApi\OpenApi;

class OpenApiFactory implements OpenApiFactoryInterface
{
    /**
     * @var OpenApiFactoryInterface
     */
    private $decorated;

    public function __construct(OpenApiFactoryInterface $decorated)
    {
        $this->decorated = $decorated;
    }

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

        /** @var PathItem $path */
        foreach ($openApi->getPaths()->getPaths() as $key => $path) {
            if ($path->getGet() && $path->getGet()->getSummary() === 'hidden') {
                $openApi->getPaths()->addPath($key, $path->withGet(null));
            }
        }

        return $openApi;
    }
}

Register it

services:
    App\OpenApi\OpenApiFactory:
        decorates: 'api_platform.openapi.factory'
        arguments: ['@App\OpenApi\OpenApiFactory.inner']
        autoconfigure: false

Add openapi_context to each route you want to hide

 * @ApiResource(
 *   itemOperations={
 *          "get"={
 *              ...
 *              "openapi_context"={
 *                  "summary"="hidden"
 *              }
 *          }
 *   }
 * )
Delirium answered 10/5, 2021 at 13:16 Comment(0)
D
6

This isn't supported out of the box (but it would be a nice contribution). What you can do is to decorate the DocumentationNormalizer to unset() the paths you don't want to appear in the OpenAPI documentation.

More information about overriding the specification in the API Platform OpenAPI documentation

Despairing answered 24/1, 2019 at 10:43 Comment(0)
M
2

As Kevin said you can unset paths & definitions you want to hide.

In my case I wanted to do the opposite, whitelisting specific actions.

# config/services.yaml
    App\Swagger\SwaggerDecorator:
            decorates: 'api_platform.swagger.normalizer.api_gateway'
            arguments: [ '@App\Swagger\SwaggerDecorator.inner' ]
            autoconfigure: false
<?php

namespace App\Swagger;

use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

final class SwaggerDecorator implements NormalizerInterface
{
    private $decorated;

    public function __construct(NormalizerInterface $decorated)
    {
        $this->decorated = $decorated;
    }

    public function normalize($object, $format = null, array $context = [])
    {
        $allowedPaths = [
            '/users',
            '/users/{id}',
        ];
        $allowedDefinitions = [
            'User',
        ];

        $docs = $this->decorated->normalize($object, $format, $context);

        $publicPaths = [];
        $publicDefinitions = [];
        foreach ($docs['paths'] as $path => $definition) {
            if (in_array($path, $allowedPaths)) {
                $publicPaths[$path] = $definition;
            }
        }
        foreach ($docs['definitions'] as $class => $definition) {
            if (in_array($class, $allowedDefinitions)) {
                $publicDefinitions[$class] = $definition;
            }
        }

        $docs['paths'] = $publicPaths;
        $docs['definitions'] = $publicDefinitions;

        return $docs;
    }

    public function supportsNormalization($data, $format = null)
    {
        return $this->decorated->supportsNormalization($data, $format);
    }
}

Muscid answered 10/11, 2020 at 14:43 Comment(2)
As of API Platform 2.6, api_platform.swagger.normalizer.api_gateway became api_platform.openapi.normalizer.api_gatewayInfantry
$docs['definitions'] no longer exists either, if using 2.6/OpenApi you will need to check within docs['components']['schemas'] insteadBlake
C
1

This is now possible in API Platform v3.2 (probably since v3). See this answer: https://mcmap.net/q/1476030/-hide-an-item-operation-api-platform.

Note that it is for Symfony 6+, which does not match the OP requirements.

Disabling an Operation From OpenAPI Documentation

#[ApiResource(
    operations: [
        new GetCollection(openapi: false)
    ]
)]
Clique answered 4/1, 2024 at 9:17 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.