Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle activation of swagger through versions #2998

@@ -56,8 +56,9 @@ final class SwaggerUiAction
private $graphqlEnabled;
private $graphiQlEnabled;
private $graphQlPlaygroundEnabled;
private $swaggerVersions;
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, NormalizerInterface $normalizer, TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '', string $version = '', $formats = [], $oauthEnabled = false, $oauthClientId = '', $oauthClientSecret = '', $oauthType = '', $oauthFlow = '', $oauthTokenUrl = '', $oauthAuthorizationUrl = '', $oauthScopes = [], bool $showWebby = true, bool $swaggerUiEnabled = false, bool $reDocEnabled = false, bool $graphqlEnabled = false, bool $graphiQlEnabled = false, bool $graphQlPlaygroundEnabled = false)
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, NormalizerInterface $normalizer, TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '', string $version = '', $formats = [], $oauthEnabled = false, $oauthClientId = '', $oauthClientSecret = '', $oauthType = '', $oauthFlow = '', $oauthTokenUrl = '', $oauthAuthorizationUrl = '', $oauthScopes = [], bool $showWebby = true, bool $swaggerUiEnabled = false, bool $reDocEnabled = false, bool $graphqlEnabled = false, bool $graphiQlEnabled = false, bool $graphQlPlaygroundEnabled = false, array $swaggerVersions = [])
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, NormalizerInterface $normalizer, TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '', string $version = '', $formats = [], $oauthEnabled = false, $oauthClientId = '', $oauthClientSecret = '', $oauthType = '', $oauthFlow = '', $oauthTokenUrl = '', $oauthAuthorizationUrl = '', $oauthScopes = [], bool $showWebby = true, bool $swaggerUiEnabled = false, bool $reDocEnabled = false, bool $graphqlEnabled = false, bool $graphiQlEnabled = false, bool $graphQlPlaygroundEnabled = false, array $swaggerVersions = [])
/**
* @var int[] $swaggerVersions
*/
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, NormalizerInterface $normalizer, TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '', string $version = '', $formats = [], $oauthEnabled = false, $oauthClientId = '', $oauthClientSecret = '', $oauthType = '', $oauthFlow = '', $oauthTokenUrl = '', $oauthAuthorizationUrl = '', $oauthScopes = [], bool $showWebby = true, bool $swaggerUiEnabled = false, bool $reDocEnabled = false, bool $graphqlEnabled = false, bool $graphiQlEnabled = false, bool $graphQlPlaygroundEnabled = false, array $swaggerVersions = [2, 3])
{
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
$this->resourceMetadataFactory = $resourceMetadataFactory;
@@ -81,6 +82,7 @@ public function __construct(ResourceNameCollectionFactoryInterface $resourceName
$this->graphqlEnabled = $graphqlEnabled;
$this->graphiQlEnabled = $graphiQlEnabled;
$this->graphQlPlaygroundEnabled = $graphQlPlaygroundEnabled;
$this->swaggerVersions = $swaggerVersions;
if (\is_array($formats)) {
$this->formats = $formats;
@@ -127,7 +129,7 @@ private function getContext(Request $request, Documentation $documentation): arr
'graphQlPlaygroundEnabled' => $this->graphQlPlaygroundEnabled,
];
$swaggerContext = ['spec_version' => $request->query->getInt('spec_version', 2)];
$swaggerContext = ['spec_version' => $request->query->getInt('spec_version', (int) ($this->swaggerVersions[0] ?? 2))];
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
$swaggerContext = ['spec_version' => $request->query->getInt('spec_version', (int) ($this->swaggerVersions[0] ?? 2))];
$swaggerContext = ['spec_version' => $request->query->getInt('spec_version', $this->swaggerVersions[0] ?? 2)];
if ('' !== $baseUrl = $request->getBaseUrl()) {
$swaggerContext['base_url'] = $baseUrl;
}
@@ -39,15 +39,17 @@ final class SwaggerCommand extends Command
private $apiDescription;
private $apiVersion;
private $apiFormats;
private $swaggerVersions;
public function __construct(NormalizerInterface $normalizer, ResourceNameCollectionFactoryInterface $resourceNameCollection, string $apiTitle, string $apiDescription, string $apiVersion, array $apiFormats = null)
public function __construct(NormalizerInterface $normalizer, ResourceNameCollectionFactoryInterface $resourceNameCollection, string $apiTitle, string $apiDescription, string $apiVersion, array $apiFormats = null, array $swaggerVersions = [2, 3])
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
public function __construct(NormalizerInterface $normalizer, ResourceNameCollectionFactoryInterface $resourceNameCollection, string $apiTitle, string $apiDescription, string $apiVersion, array $apiFormats = null, array $swaggerVersions = [2, 3])
/**
* @var int[] $swaggerVersions
*/
public function __construct(NormalizerInterface $normalizer, ResourceNameCollectionFactoryInterface $resourceNameCollection, string $apiTitle, string $apiDescription, string $apiVersion, array $apiFormats = null, array $swaggerVersions = [2, 3])
{
$this->normalizer = $normalizer;
$this->resourceNameCollectionFactory = $resourceNameCollection;
$this->apiTitle = $apiTitle;
$this->apiDescription = $apiDescription;
$this->apiVersion = $apiVersion;
$this->apiFormats = $apiFormats;
$this->swaggerVersions = $swaggerVersions;
if (null !== $apiFormats) {
@trigger_error(sprintf('Passing a 6th parameter to the constructor of "%s" is deprecated since API Platform 2.5', __CLASS__), E_USER_DEPRECATED);
@@ -66,7 +68,7 @@ protected function configure()
->setAliases(['api:swagger:export'])
->setDescription('Dump the OpenAPI documentation')
->addOption('yaml', 'y', InputOption::VALUE_NONE, 'Dump the documentation in YAML')
->addOption('spec-version', null, InputOption::VALUE_OPTIONAL, 'OpenAPI version to use ("2" or "3")', '2')
->addOption('spec-version', null, InputOption::VALUE_OPTIONAL, sprintf('OpenAPI version to use (%s)', implode(' or ', $this->swaggerVersions)), (string) ($this->swaggerVersions[0] ?? '2'))
->addOption('output', 'o', InputOption::VALUE_OPTIONAL, 'Write output to file')
->addOption('api-gateway', null, InputOption::VALUE_NONE, 'API Gateway compatibility');
}
@@ -77,11 +79,15 @@ protected function configure()
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
/** @var string $spec_version */
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
/** @var string $spec_version */
/** @var string $specVersion */
$spec_version = $input->getOption('spec-version');
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
$spec_version = $input->getOption('spec-version');
$specVersion = (int) $input->getOption('spec-version');
/** @var string $version */
$version = $input->getOption('spec-version');
$version = explode('.', $spec_version)[0];
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
$version = explode('.', $spec_version)[0];
if (!\in_array($version, ['2', '3'], true)) {
throw new InvalidOptionException(sprintf('This tool only supports version 2 and 3 of the OpenAPI specification ("%s" given).', $version));
if (!\in_array($version, $this->swaggerVersions, true)) {
throw new InvalidOptionException(sprintf('This tool only supports version %s of the OpenAPI specification ("%s" given).', implode(', ', $this->swaggerVersions), $version));
}
$documentation = new Documentation($this->resourceNameCollectionFactory->create(), $this->apiTitle, $this->apiDescription, $this->apiVersion, $this->apiFormats);
@@ -308,6 +308,10 @@ private function registerOAuthConfiguration(ContainerBuilder $container, array $
private function registerSwaggerConfiguration(ContainerBuilder $container, array $config, XmlFileLoader $loader): void
{
if (!$config['enable_swagger']) {
@trigger_error('The "api_platform.enable_swagger" parameter is deprecated since version 2.5 and will have no effect in 3.0. Please use "api_platform.swagger.versions" instead.', E_USER_DEPRECATED);
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member

to remove

}
if (empty($config['swagger']['versions'])) {
return;
}
@@ -320,7 +324,7 @@ private function registerSwaggerConfiguration(ContainerBuilder $container, array
$container->setParameter('api_platform.enable_re_doc', $config['enable_re_doc']);
}
$container->setParameter('api_platform.enable_swagger', $config['enable_swagger']);
$container->setParameter('api_platform.swagger.versions', $config['swagger']['versions']);
$container->setParameter('api_platform.swagger.api_keys', $config['swagger']['api_keys']);
}
@@ -56,6 +56,16 @@ public function getConfigTreeBuilder()
}
$rootNode
->beforeNormalization()
->ifTrue(static function ($v) {
return isset($v['enable_swagger']) && false === $v['enable_swagger'];
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
return isset($v['enable_swagger']) && false === $v['enable_swagger'];
return false === ($v['enable_swagger'] ?? null);
})
->then(static function ($v) {
$v['swagger']['versions'] = [];
return $v;
})
->end()
->children()
->scalarNode('title')
->info('The title of the API.')
@@ -102,7 +112,11 @@ public function getConfigTreeBuilder()
->setDeprecated('Enabling the NelmioApiDocBundle integration has been deprecated in 2.2 and will be removed in 3.0. NelmioApiDocBundle 3 has native support for API Platform.')
->info('Enable the NelmioApiDocBundle integration.')
->end()
->booleanNode('enable_swagger')->defaultTrue()->info('Enable the Swagger documentation and export.')->end()
->booleanNode('enable_swagger')
->defaultTrue()
->setDeprecated('The use of `enable_swagger` has been deprecated in 2.5 and will be removed in 3.0. use `api_platform.swagger.versions` instead.')
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member

to remove

->info('Enable the Swagger documentation and export.')
->end()
->booleanNode('enable_swagger_ui')->defaultValue(class_exists(TwigBundle::class))->info('Enable Swagger UI')->end()
->booleanNode('enable_re_doc')->defaultValue(class_exists(TwigBundle::class))->info('Enable ReDoc')->end()
->booleanNode('enable_entrypoint')->defaultTrue()->info('Enable the entrypoint')->end()
@@ -236,14 +250,28 @@ private function addGraphQlSection(ArrayNodeDefinition $rootNode): void
private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
{
$defaultVersions = ['2', '3'];
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
$defaultVersions = ['2', '3'];
$defaultVersions = [2, 3];
$rootNode
->children()
->arrayNode('swagger')
->addDefaultsIfNotSet()
->children()
->arrayNode('api_keys')
->prototype('array')
->children()
->arrayNode('versions')
->info('The active versions of OpenAPI to be exported or used in the swagger_ui. The first value is the default.')
->defaultValue($defaultVersions)
->beforeNormalization()->castToArray()->end()
->validate()
->ifTrue(function ($v) use ($defaultVersions) {
return $v !== array_intersect($v, $defaultVersions);
})
->thenInvalid(sprintf('Only the versions %s are supported. Got %s.', implode(' and ', $defaultVersions), '%s'))
->end()
->prototype('scalar')->end()
->end()
->arrayNode('api_keys')
->prototype('array')
->children()
->scalarNode('name')
->info('The name of the header or query parameter containing the api key.')
->end()
@@ -252,7 +280,7 @@ private function addSwaggerSection(ArrayNodeDefinition $rootNode): void
->values(['query', 'header'])
->end()
->end()
->end()
->end()
->end()
->end()
->end()
@@ -240,6 +240,8 @@
<argument>%api_platform.title%</argument>
<argument>%api_platform.description%</argument>
<argument>%api_platform.version%</argument>
<argument>null</argument>
<argument on-invalid="null">%api_platform.swagger.versions%</argument>
This conversation was marked as resolved by dunglas

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
<argument on-invalid="null">%api_platform.swagger.versions%</argument>
<argument>%api_platform.swagger.versions%</argument>

This parameter is always defined isn't it?

This comment has been minimized.

Copy link
@GregoireHebert

GregoireHebert Aug 20, 2019

Author Contributor

no, it's not.
As soon as the configuration swagger version is an empty array, this parameter is not set.
This follow the same logic as for the api_platform.swagger.api_keys parameter.

</service>

<service id="api_platform.action.exception" class="ApiPlatform\Core\Action\ExceptionAction" public="true">
@@ -34,6 +34,7 @@
<argument>%api_platform.graphql.enabled%</argument>
<argument>%api_platform.graphql.graphiql.enabled%</argument>
<argument>%api_platform.graphql.graphql_playground.enabled%</argument>
<argument>%api_platform.swagger.versions%</argument>
</service>

</services>
@@ -31,6 +31,7 @@
<argument>%api_platform.formats%</argument>
<argument>%api_platform.collection.pagination.client_enabled%</argument>
<argument>%api_platform.collection.pagination.enabled_parameter_name%</argument>
<argument>%api_platform.swagger.versions%</argument>
<tag name="serializer.normalizer" priority="-790" />
</service>

@@ -45,6 +46,8 @@
<argument>%api_platform.title%</argument>
<argument>%api_platform.description%</argument>
<argument>%api_platform.version%</argument>
<argument>null</argument>
<argument>%api_platform.swagger.versions%</argument>
<tag name="console.command" />
</service>

@@ -32,14 +32,15 @@ final class DocumentationAction
private $version;
private $formats;
private $formatsProvider;
private $resourceMetadataFactory;
private $swaggerVersions;
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, string $title = '', string $description = '', string $version = '', $formatsProvider = null)
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, string $title = '', string $description = '', string $version = '', $formatsProvider = null, ?array $swaggerVersions = [])
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, string $title = '', string $description = '', string $version = '', $formatsProvider = null, ?array $swaggerVersions = [])
/**
* @param int[] $swaggerVersions
*/
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, string $title = '', string $description = '', string $version = '', $formatsProvider = null, array $swaggerVersions = [2, 3])
{
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
$this->title = $title;
$this->description = $description;
$this->version = $version;
$this->swaggerVersions = $swaggerVersions;
if (null === $formatsProvider) {
return;
@@ -57,7 +58,7 @@ public function __construct(ResourceNameCollectionFactoryInterface $resourceName
public function __invoke(Request $request = null): Documentation
{
if (null !== $request) {
$context = ['base_url' => $request->getBaseUrl(), 'spec_version' => $request->query->getInt('spec_version', 2)];
$context = ['base_url' => $request->getBaseUrl(), 'spec_version' => $request->query->getInt('spec_version', (int) ($this->swaggerVersions[0] ?? 2))];
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
$context = ['base_url' => $request->getBaseUrl(), 'spec_version' => $request->query->getInt('spec_version', (int) ($this->swaggerVersions[0] ?? 2))];
$context = ['base_url' => $request->getBaseUrl(), 'spec_version' => $request->query->getInt('spec_version', $this->swaggerVersions[0] ?? 2)];
if ($request->query->getBoolean('api_gateway')) {
$context['api_gateway'] = true;
}
@@ -95,7 +95,6 @@ final class DocumentationNormalizer implements NormalizerInterface, CacheableSup
private $jsonSchemaTypeFactory;
private $defaultContext = [
self::BASE_URL => '/',
self::SPEC_VERSION => 2,
ApiGatewayNormalizer::API_GATEWAY => false,
];
@@ -105,7 +104,7 @@ final class DocumentationNormalizer implements NormalizerInterface, CacheableSup
* @param array|OperationAwareFormatsProviderInterface $formats
* @param mixed|null $jsonSchemaTypeFactory
*/
public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, $jsonSchemaFactory = null, $jsonSchemaTypeFactory = null, OperationPathResolverInterface $operationPathResolver, UrlGeneratorInterface $urlGenerator = null, $filterLocator = null, NameConverterInterface $nameConverter = null, bool $oauthEnabled = false, string $oauthType = '', string $oauthFlow = '', string $oauthTokenUrl = '', string $oauthAuthorizationUrl = '', array $oauthScopes = [], array $apiKeys = [], SubresourceOperationFactoryInterface $subresourceOperationFactory = null, bool $paginationEnabled = true, string $paginationPageParameterName = 'page', bool $clientItemsPerPage = false, string $itemsPerPageParameterName = 'itemsPerPage', $formats = [], bool $paginationClientEnabled = false, string $paginationClientEnabledParameterName = 'pagination', array $defaultContext = [])
public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, $jsonSchemaFactory = null, $jsonSchemaTypeFactory = null, OperationPathResolverInterface $operationPathResolver, UrlGeneratorInterface $urlGenerator = null, $filterLocator = null, NameConverterInterface $nameConverter = null, bool $oauthEnabled = false, string $oauthType = '', string $oauthFlow = '', string $oauthTokenUrl = '', string $oauthAuthorizationUrl = '', array $oauthScopes = [], array $apiKeys = [], SubresourceOperationFactoryInterface $subresourceOperationFactory = null, bool $paginationEnabled = true, string $paginationPageParameterName = 'page', bool $clientItemsPerPage = false, string $itemsPerPageParameterName = 'itemsPerPage', $formats = [], bool $paginationClientEnabled = false, string $paginationClientEnabledParameterName = 'pagination', array $defaultContext = [], array $versions = [2, 3])
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member

Add the phpdoc for int[] for $swaggerVersions

{
if ($jsonSchemaTypeFactory instanceof OperationMethodResolverInterface) {
@trigger_error(sprintf('Passing an instance of %s to %s() is deprecated since version 2.5 and will be removed in 3.0.', OperationMethodResolverInterface::class, __METHOD__), E_USER_DEPRECATED);
@@ -163,6 +162,8 @@ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFa
$this->paginationClientEnabled = $paginationClientEnabled;
$this->paginationClientEnabledParameterName = $paginationClientEnabledParameterName;
$this->defaultContext[self::SPEC_VERSION] = (int) ($versions[0] ?? '2');
This conversation was marked as resolved by dunglas

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 19, 2019

Member

Same here (what about the empty string).

This comment has been minimized.

Copy link
@GregoireHebert

GregoireHebert Aug 20, 2019

Author Contributor

Nah, this one is coming from the configuration. It can't be an empty string there.
But.
This Normalizer comes from the api.xml file.
I had to handle the emptiness only because this service is not part of the swagger.xml file. Is it something we should change?

This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
$this->defaultContext[self::SPEC_VERSION] = (int) ($versions[0] ?? '2');
$this->defaultContext[self::SPEC_VERSION] = $versions[0] ?? 2;
$this->defaultContext = array_merge($this->defaultContext, $defaultContext);
}
@@ -105,7 +105,7 @@ public function testExecuteOpenApiVersion2WithYaml()
public function testExecuteWithBadArguments()
{
$this->expectException(InvalidOptionException::class);
$this->expectExceptionMessage('This tool only supports version 2 and 3 of the OpenAPI specification ("foo" given).');
$this->expectExceptionMessage('This tool only supports version 2, 3 of the OpenAPI specification ("foo" given).');
This conversation was marked as resolved by GregoireHebert

This comment has been minimized.

Copy link
@dunglas

dunglas Aug 20, 2019

Member
Suggested change
$this->expectExceptionMessage('This tool only supports version 2, 3 of the OpenAPI specification ("foo" given).');
$this->expectExceptionMessage('This tool only supports versions 2, 3 of the OpenAPI specification ("foo" given).');
$this->tester->run(['command' => 'api:openapi:export', '--spec-version' => 'foo', '--yaml' => true]);
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.