Skip to content

Commit

Permalink
feat(openapi): disable response override (#6221)
Browse files Browse the repository at this point in the history
fixes #6151
  • Loading branch information
soyuka authored Mar 15, 2024
1 parent 71b4f35 commit 5523bf5
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 33 deletions.
8 changes: 8 additions & 0 deletions features/openapi/docs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ Feature: Documentation support
}
}
"""
And the JSON node "paths./override_open_api_responses.post.responses" should be equal to:
"""
{
"204": {
"description": "User activated"
}
}
"""

Scenario: OpenAPI UI is enabled for docs endpoint
Given I add "Accept" header equal to "text/html"
Expand Down
69 changes: 37 additions & 32 deletions src/OpenApi/Factory/OpenApiFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ final class OpenApiFactory implements OpenApiFactoryInterface
use NormalizeOperationNameTrait;

public const BASE_URL = 'base_url';
public const OVERRIDE_OPENAPI_RESPONSES = 'open_api_override_responses';
private readonly Options $openApiOptions;
private readonly PaginationOptions $paginationOptions;
private ?RouteCollection $routeCollection = null;
Expand Down Expand Up @@ -284,37 +285,40 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
}

$existingResponses = $openapiOperation?->getResponses() ?: [];
// Create responses
switch ($method) {
case 'GET':
$successStatus = (string) $operation->getStatus() ?: 200;
$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s %s', $resourceShortName, $operation instanceof CollectionOperationInterface ? 'collection' : 'resource'), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas);
break;
case 'POST':
$successStatus = (string) $operation->getStatus() ?: 201;

$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource created', $resourceShortName), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas, $resourceMetadataCollection);

$openapiOperation = $this->buildOpenApiResponse($existingResponses, '400', 'Invalid input', $openapiOperation);

$openapiOperation = $this->buildOpenApiResponse($existingResponses, '422', 'Unprocessable entity', $openapiOperation);
break;
case 'PATCH':
case 'PUT':
$successStatus = (string) $operation->getStatus() ?: 200;
$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource updated', $resourceShortName), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas, $resourceMetadataCollection);
$openapiOperation = $this->buildOpenApiResponse($existingResponses, '400', 'Invalid input', $openapiOperation);
if (!isset($existingResponses[400])) {
$openapiOperation = $openapiOperation->withResponse(400, new Response('Invalid input'));
}
$openapiOperation = $this->buildOpenApiResponse($existingResponses, '422', 'Unprocessable entity', $openapiOperation);
break;
case 'DELETE':
$successStatus = (string) $operation->getStatus() ?: 204;

$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource deleted', $resourceShortName), $openapiOperation);

break;
$overrideResponses = $operation->getExtraProperties()[self::OVERRIDE_OPENAPI_RESPONSES] ?? $this->openApiOptions->getOverrideResponses();
if ($overrideResponses || !$existingResponses) {
// Create responses
switch ($method) {
case 'GET':
$successStatus = (string) $operation->getStatus() ?: 200;
$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s %s', $resourceShortName, $operation instanceof CollectionOperationInterface ? 'collection' : 'resource'), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas);
break;
case 'POST':
$successStatus = (string) $operation->getStatus() ?: 201;

$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource created', $resourceShortName), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas, $resourceMetadataCollection);

$openapiOperation = $this->buildOpenApiResponse($existingResponses, '400', 'Invalid input', $openapiOperation);

$openapiOperation = $this->buildOpenApiResponse($existingResponses, '422', 'Unprocessable entity', $openapiOperation);
break;
case 'PATCH':
case 'PUT':
$successStatus = (string) $operation->getStatus() ?: 200;
$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource updated', $resourceShortName), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas, $resourceMetadataCollection);
$openapiOperation = $this->buildOpenApiResponse($existingResponses, '400', 'Invalid input', $openapiOperation);
if (!isset($existingResponses[400])) {
$openapiOperation = $openapiOperation->withResponse(400, new Response('Invalid input'));
}
$openapiOperation = $this->buildOpenApiResponse($existingResponses, '422', 'Unprocessable entity', $openapiOperation);
break;
case 'DELETE':
$successStatus = (string) $operation->getStatus() ?: 204;

$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource deleted', $resourceShortName), $openapiOperation);

break;
}
}

if (!$operation instanceof CollectionOperationInterface && 'POST' !== $operation->getMethod()) {
Expand Down Expand Up @@ -594,7 +598,8 @@ private function getFiltersParameters(CollectionOperationInterface|HttpOperation
$data['openapi']['explode'] ?? ('array' === $schema['type']),
$data['openapi']['allowReserved'] ?? false,
$data['openapi']['example'] ?? null,
isset($data['openapi']['examples']
isset(
$data['openapi']['examples']
) ? new \ArrayObject($data['openapi']['examples']) : null
);
}
Expand Down
7 changes: 6 additions & 1 deletion src/OpenApi/Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

final class Options
{
public function __construct(private readonly string $title, private readonly string $description = '', private readonly string $version = '', private readonly bool $oAuthEnabled = false, private readonly ?string $oAuthType = null, private readonly ?string $oAuthFlow = null, private readonly ?string $oAuthTokenUrl = null, private readonly ?string $oAuthAuthorizationUrl = null, private readonly ?string $oAuthRefreshUrl = null, private readonly array $oAuthScopes = [], private readonly array $apiKeys = [], private readonly ?string $contactName = null, private readonly ?string $contactUrl = null, private readonly ?string $contactEmail = null, private readonly ?string $termsOfService = null, private readonly ?string $licenseName = null, private readonly ?string $licenseUrl = null)
public function __construct(private readonly string $title, private readonly string $description = '', private readonly string $version = '', private readonly bool $oAuthEnabled = false, private readonly ?string $oAuthType = null, private readonly ?string $oAuthFlow = null, private readonly ?string $oAuthTokenUrl = null, private readonly ?string $oAuthAuthorizationUrl = null, private readonly ?string $oAuthRefreshUrl = null, private readonly array $oAuthScopes = [], private readonly array $apiKeys = [], private readonly ?string $contactName = null, private readonly ?string $contactUrl = null, private readonly ?string $contactEmail = null, private readonly ?string $termsOfService = null, private readonly ?string $licenseName = null, private readonly ?string $licenseUrl = null, private bool $overrideResponses = true)
{
}

Expand Down Expand Up @@ -103,4 +103,9 @@ public function getLicenseUrl(): ?string
{
return $this->licenseUrl;
}

public function getOverrideResponses(): bool
{
return $this->overrideResponses;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,7 @@ private function registerOpenApiConfiguration(ContainerBuilder $container, array
$container->setParameter('api_platform.openapi.contact.email', $config['openapi']['contact']['email']);
$container->setParameter('api_platform.openapi.license.name', $config['openapi']['license']['name']);
$container->setParameter('api_platform.openapi.license.url', $config['openapi']['license']['url']);
$container->setParameter('api_platform.openapi.overrideResponses', $config['openapi']['overrideResponses']);

$loader->load('json_schema.xml');
}
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ private function addOpenApiSection(ArrayNodeDefinition $rootNode): void
->end()
->info('To pass extra configuration to Swagger UI, like docExpansion or filter.')
->end()
->booleanNode('overrideResponses')->defaultTrue()->info('Whether API Platform adds automatic responses to the OpenAPI documentation.')
->end()
->end()
->end();
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/Resources/config/openapi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<argument>%api_platform.openapi.termsOfService%</argument>
<argument>%api_platform.openapi.license.name%</argument>
<argument>%api_platform.openapi.license.url%</argument>
<argument>%api_platform.openapi.overrideResponses%</argument>
</service>
<service id="ApiPlatform\OpenApi\Options" alias="api_platform.openapi.options" />

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6151;

use ApiPlatform\Metadata\Post;
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
use ApiPlatform\OpenApi\Model\Operation;
use ApiPlatform\OpenApi\Model\Response;

#[Post(
uriTemplate: '/override_open_api_responses',
openapi: new Operation(
responses: [
'204' => new Response(
description: 'User activated',
),
]
),
extraProperties: [OpenApiFactory::OVERRIDE_OPENAPI_RESPONSES => false],
)]
final class OverrideOpenApiResponses
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm
'url' => null,
],
'swagger_ui_extra_configuration' => [],
'overrideResponses' => true,
],
'maker' => [
'enabled' => true,
Expand Down

0 comments on commit 5523bf5

Please sign in to comment.