mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 15:51:48 +03:00
Add areas support (#1169)
* Add areas support * Document the Areas feature * Allow to expose swagger area as JSON * Fixes * last fixes
This commit is contained in:
parent
92f3eb633b
commit
393a6c061e
@ -7,3 +7,5 @@ enabled:
|
||||
|
||||
disabled:
|
||||
- unalign_equals
|
||||
- braces
|
||||
- property_separation
|
||||
|
@ -32,11 +32,12 @@ final class ApiDocGenerator
|
||||
* @param DescriberInterface[]|iterable $describers
|
||||
* @param ModelDescriberInterface[]|iterable $modelDescribers
|
||||
*/
|
||||
public function __construct($describers, $modelDescribers, CacheItemPoolInterface $cacheItemPool = null)
|
||||
public function __construct($describers, $modelDescribers, CacheItemPoolInterface $cacheItemPool = null, string $cacheItemId = null)
|
||||
{
|
||||
$this->describers = $describers;
|
||||
$this->modelDescribers = $modelDescribers;
|
||||
$this->cacheItemPool = $cacheItemPool;
|
||||
$this->cacheItemId = $cacheItemId;
|
||||
}
|
||||
|
||||
public function generate(): Swagger
|
||||
@ -46,7 +47,7 @@ final class ApiDocGenerator
|
||||
}
|
||||
|
||||
if ($this->cacheItemPool) {
|
||||
$item = $this->cacheItemPool->getItem('swagger_doc');
|
||||
$item = $this->cacheItemPool->getItem($this->cacheItemId ?? 'swagger_doc');
|
||||
if ($item->isHit()) {
|
||||
return $this->swagger = $item->get();
|
||||
}
|
||||
|
15
CHANGELOG.md
15
CHANGELOG.md
@ -15,6 +15,21 @@ JMS Serializer
|
||||
SwaggerPHP
|
||||
* Handle `enum` and `default` properties from SwaggerPHP annotation
|
||||
|
||||
Config
|
||||
* `nelmio_api_doc.routes` has been replaced by `nelmio_api_doc.areas`. Please update your config accordingly.
|
||||
|
||||
Before:
|
||||
```yml
|
||||
nelmio_api_doc:
|
||||
routes: [ path_patterns: [ /api ] ]
|
||||
```
|
||||
|
||||
After:
|
||||
```yml
|
||||
nelmio_api_doc:
|
||||
areas: [ path_patterns: [ /api ] ]
|
||||
```
|
||||
|
||||
3.0.0 (2017-12-10)
|
||||
------------------
|
||||
|
||||
|
@ -12,21 +12,42 @@
|
||||
namespace Nelmio\ApiDocBundle\Controller;
|
||||
|
||||
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
final class DocumentationController
|
||||
{
|
||||
private $apiDocGenerator;
|
||||
private $generatorLocator;
|
||||
|
||||
public function __construct(ApiDocGenerator $apiDocGenerator)
|
||||
/**
|
||||
* @param ContainerInterface $generatorLocator
|
||||
*/
|
||||
public function __construct($generatorLocator)
|
||||
{
|
||||
$this->apiDocGenerator = $apiDocGenerator;
|
||||
if (!$generatorLocator instanceof ContainerInterface) {
|
||||
if (!$generatorLocator instanceof ApiDocGenerator) {
|
||||
throw new \InvalidArgumentException(sprintf('Providing an instance of "%s" to "%s" is not supported.', get_class($generatorLocator), __METHOD__));
|
||||
}
|
||||
|
||||
@trigger_error(sprintf('Providing an instance of "%s" to "%s()" is deprecated since version 3.1. Provide it an instance of "%s" instead.', ApiDocGenerator::class, __METHOD__, ContainerInterface::class), E_USER_DEPRECATED);
|
||||
$generatorLocator = new ServiceLocator(['default' => function () use ($generatorLocator): ApiDocGenerator {
|
||||
return $generatorLocator;
|
||||
}]);
|
||||
}
|
||||
|
||||
$this->generatorLocator = $generatorLocator;
|
||||
}
|
||||
|
||||
public function __invoke(Request $request)
|
||||
public function __invoke(Request $request, $area = 'default')
|
||||
{
|
||||
$spec = $this->apiDocGenerator->generate()->toArray();
|
||||
if (!$this->generatorLocator->has($area)) {
|
||||
throw new BadRequestHttpException(sprintf('Area "%s" is not supported.', $area));
|
||||
}
|
||||
|
||||
$spec = $this->generatorLocator->get($area)->generate()->toArray();
|
||||
if ('' !== $request->getBaseUrl()) {
|
||||
$spec['basePath'] = $request->getBaseUrl();
|
||||
}
|
||||
|
@ -12,24 +12,45 @@
|
||||
namespace Nelmio\ApiDocBundle\Controller;
|
||||
|
||||
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
final class SwaggerUiController
|
||||
{
|
||||
private $apiDocGenerator;
|
||||
private $generatorLocator;
|
||||
|
||||
private $twig;
|
||||
|
||||
public function __construct(ApiDocGenerator $apiDocGenerator, \Twig_Environment $twig)
|
||||
/**
|
||||
* @param ContainerInterface $generatorLocator
|
||||
*/
|
||||
public function __construct($generatorLocator, \Twig_Environment $twig)
|
||||
{
|
||||
$this->apiDocGenerator = $apiDocGenerator;
|
||||
if (!$generatorLocator instanceof ContainerInterface) {
|
||||
if (!$generatorLocator instanceof ApiDocGenerator) {
|
||||
throw new \InvalidArgumentException(sprintf('Providing an instance of "%s" to "%s" is not supported.', get_class($generatorLocator), __METHOD__));
|
||||
}
|
||||
|
||||
@trigger_error(sprintf('Providing an instance of "%s" to "%s()" is deprecated since version 3.1. Provide it an instance of "%s" instead.', ApiDocGenerator::class, __METHOD__, ContainerInterface::class), E_USER_DEPRECATED);
|
||||
$generatorLocator = new ServiceLocator(['default' => function () use ($generatorLocator): ApiDocGenerator {
|
||||
return $generatorLocator;
|
||||
}]);
|
||||
}
|
||||
|
||||
$this->generatorLocator = $generatorLocator;
|
||||
$this->twig = $twig;
|
||||
}
|
||||
|
||||
public function __invoke(Request $request)
|
||||
public function __invoke(Request $request, $area = 'default')
|
||||
{
|
||||
$spec = $this->apiDocGenerator->generate()->toArray();
|
||||
if (!$this->generatorLocator->has($area)) {
|
||||
throw new BadRequestHttpException(sprintf('Area "%s" is not supported.', $area));
|
||||
}
|
||||
|
||||
$spec = $this->generatorLocator->get($area)->generate()->toArray();
|
||||
if ('' !== $request->getBaseUrl()) {
|
||||
$spec['basePath'] = $request->getBaseUrl();
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class AddModelDescribersPass implements CompilerPassInterface
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$modelDescribers = $this->findAndSortTaggedServices('nelmio_api_doc.model_describer', $container);
|
||||
|
||||
$container->getDefinition('nelmio_api_doc.generator')->replaceArgument(1, $modelDescribers);
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class AddRouteDescribersPass implements CompilerPassInterface
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$routeDescribers = $this->findAndSortTaggedServices('nelmio_api_doc.route_describer', $container);
|
||||
|
||||
$container->getDefinition('nelmio_api_doc.describers.route')->replaceArgument(2, $routeDescribers);
|
||||
}
|
||||
}
|
@ -12,20 +12,22 @@
|
||||
namespace Nelmio\ApiDocBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class AddDescribersPass implements CompilerPassInterface
|
||||
final class TagDescribersPass implements CompilerPassInterface
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$describers = $this->findAndSortTaggedServices('nelmio_api_doc.describer', $container);
|
||||
|
||||
$container->getDefinition('nelmio_api_doc.generator')->replaceArgument(0, $describers);
|
||||
foreach ($container->findTaggedServiceIds('nelmio_api_doc.describer') as $id => $tags) {
|
||||
$describer = $container->getDefinition($id);
|
||||
foreach ($container->getParameter('nelmio_api_doc.areas') as $area) {
|
||||
foreach ($tags as $tag) {
|
||||
$describer->addTag(sprintf('nelmio_api_doc.describer.%s', $area), $tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,24 @@ final class Configuration implements ConfigurationInterface
|
||||
$treeBuilder = new TreeBuilder();
|
||||
$treeBuilder
|
||||
->root('nelmio_api_doc')
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) {
|
||||
return !isset($v['areas']) && isset($v['routes']);
|
||||
})
|
||||
->then(function ($v) {
|
||||
$v['areas'] = $v['routes'];
|
||||
unset($v['routes']);
|
||||
@trigger_error('The `nelmio_api_doc.routes` config option is deprecated. Please use `nelmio_api_doc.areas` instead (just replace `routes` by `areas` in your config).', E_USER_DEPRECATED);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) {
|
||||
return isset($v['routes']);
|
||||
})
|
||||
->thenInvalid('You must not use both `nelmio_api_doc.areas` and `nelmio_api_doc.routes` config options. Please update your config to only use `nelmio_api_doc.areas`.')
|
||||
->end()
|
||||
->children()
|
||||
->arrayNode('documentation')
|
||||
->useAttributeAsKey('key')
|
||||
@ -28,13 +46,30 @@ final class Configuration implements ConfigurationInterface
|
||||
->example(['info' => ['title' => 'My App']])
|
||||
->prototype('variable')->end()
|
||||
->end()
|
||||
->arrayNode('routes')
|
||||
->arrayNode('areas')
|
||||
->info('Filter the routes that are documented')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->arrayNode('path_patterns')
|
||||
->example(['^/api', '^/api(?!/admin)'])
|
||||
->prototype('scalar')->end()
|
||||
->beforeNormalization()
|
||||
->ifTrue(function ($v) {
|
||||
return empty($v) or isset($v['path_patterns']);
|
||||
})
|
||||
->then(function ($v) {
|
||||
return ['default' => $v];
|
||||
})
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
return !isset($v['default']);
|
||||
})
|
||||
->thenInvalid('You must specify a `default` area under `nelmio_api_doc.areas`.')
|
||||
->end()
|
||||
->useAttributeAsKey('name')
|
||||
->prototype('array')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->arrayNode('path_patterns')
|
||||
->example(['^/api', '^/api(?!/admin)'])
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
@ -12,10 +12,14 @@
|
||||
namespace Nelmio\ApiDocBundle\DependencyInjection;
|
||||
|
||||
use FOS\RestBundle\Controller\Annotations\ParamInterface;
|
||||
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
||||
use Nelmio\ApiDocBundle\Describer\RouteDescriber;
|
||||
use Nelmio\ApiDocBundle\Describer\SwaggerPhpDescriber;
|
||||
use Nelmio\ApiDocBundle\ModelDescriber\JMSModelDescriber;
|
||||
use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder;
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
@ -54,22 +58,57 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
||||
$routesDefinition = (new Definition(RouteCollection::class))
|
||||
->setFactory([new Reference('router'), 'getRouteCollection']);
|
||||
|
||||
if (0 === count($config['routes']['path_patterns'])) {
|
||||
$container->setDefinition('nelmio_api_doc.routes', $routesDefinition)
|
||||
->setPublic(false);
|
||||
} else {
|
||||
$container->register('nelmio_api_doc.routes', RouteCollection::class)
|
||||
$container->setParameter('nelmio_api_doc.areas', array_keys($config['areas']));
|
||||
foreach ($config['areas'] as $area => $areaConfig) {
|
||||
$container->register(sprintf('nelmio_api_doc.generator.%s', $area), ApiDocGenerator::class)
|
||||
->setPublic(false)
|
||||
->setFactory([
|
||||
(new Definition(FilteredRouteCollectionBuilder::class))
|
||||
->addArgument($config['routes']['path_patterns']),
|
||||
'filter',
|
||||
->setArguments([
|
||||
new TaggedIteratorArgument(sprintf('nelmio_api_doc.describer.%s', $area)),
|
||||
new TaggedIteratorArgument('nelmio_api_doc.model_describer'),
|
||||
]);
|
||||
|
||||
if (0 === count($areaConfig['path_patterns'])) {
|
||||
$container->setDefinition(sprintf('nelmio_api_doc.routes.%s', $area), $routesDefinition)
|
||||
->setPublic(false);
|
||||
} else {
|
||||
$container->register(sprintf('nelmio_api_doc.routes.%s', $area), RouteCollection::class)
|
||||
->setPublic(false)
|
||||
->setFactory([
|
||||
(new Definition(FilteredRouteCollectionBuilder::class))
|
||||
->addArgument($areaConfig['path_patterns']),
|
||||
'filter',
|
||||
])
|
||||
->addArgument($routesDefinition);
|
||||
}
|
||||
|
||||
$container->register(sprintf('nelmio_api_doc.describers.route.%s', $area), RouteDescriber::class)
|
||||
->setPublic(false)
|
||||
->setArguments([
|
||||
new Reference(sprintf('nelmio_api_doc.routes.%s', $area)),
|
||||
new Reference('nelmio_api_doc.controller_reflector'),
|
||||
new TaggedIteratorArgument('nelmio_api_doc.route_describer'),
|
||||
])
|
||||
->addArgument($routesDefinition);
|
||||
->addTag(sprintf('nelmio_api_doc.describer.%s', $area), ['priority' => -400]);
|
||||
|
||||
$container->register(sprintf('nelmio_api_doc.describers.swagger_php.%s', $area), SwaggerPhpDescriber::class)
|
||||
->setPublic(false)
|
||||
->setArguments([
|
||||
new Reference(sprintf('nelmio_api_doc.routes.%s', $area)),
|
||||
new Reference('nelmio_api_doc.controller_reflector'),
|
||||
new Reference('annotation_reader'),
|
||||
])
|
||||
->addTag(sprintf('nelmio_api_doc.describer.%s', $area), ['priority' => -200]);
|
||||
}
|
||||
|
||||
$container->register('nelmio_api_doc.generator_locator')
|
||||
->setPublic(false)
|
||||
->addTag('container.service_locator')
|
||||
->addArgument(array_combine(
|
||||
array_keys($config['areas']),
|
||||
array_map(function ($area) { return new Reference(sprintf('nelmio_api_doc.generator.%s', $area)); }, array_keys($config['areas']))
|
||||
));
|
||||
|
||||
// Import services needed for each library
|
||||
$loader->load('swagger_php.xml');
|
||||
if (class_exists(DocBlockFactory::class)) {
|
||||
$loader->load('php_doc.xml');
|
||||
}
|
||||
|
@ -11,10 +11,8 @@
|
||||
|
||||
namespace Nelmio\ApiDocBundle;
|
||||
|
||||
use Nelmio\ApiDocBundle\DependencyInjection\Compiler\AddDescribersPass;
|
||||
use Nelmio\ApiDocBundle\DependencyInjection\Compiler\AddModelDescribersPass;
|
||||
use Nelmio\ApiDocBundle\DependencyInjection\Compiler\AddRouteDescribersPass;
|
||||
use Nelmio\ApiDocBundle\DependencyInjection\Compiler\ConfigurationPass;
|
||||
use Nelmio\ApiDocBundle\DependencyInjection\Compiler\TagDescribersPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
@ -26,8 +24,6 @@ final class NelmioApiDocBundle extends Bundle
|
||||
public function build(ContainerBuilder $container)
|
||||
{
|
||||
$container->addCompilerPass(new ConfigurationPass());
|
||||
$container->addCompilerPass(new AddDescribersPass());
|
||||
$container->addCompilerPass(new AddModelDescribersPass());
|
||||
$container->addCompilerPass(new AddRouteDescribersPass());
|
||||
$container->addCompilerPass(new TagDescribersPass());
|
||||
}
|
||||
}
|
||||
|
@ -6,19 +6,16 @@
|
||||
<services>
|
||||
<!-- Controllers -->
|
||||
<service id="nelmio_api_doc.controller.swagger_ui" class="Nelmio\ApiDocBundle\Controller\SwaggerUiController" public="true">
|
||||
<argument type="service" id="nelmio_api_doc.generator" />
|
||||
<argument type="service" id="nelmio_api_doc.generator_locator" />
|
||||
<argument type="service" id="twig" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.controller.swagger" class="Nelmio\ApiDocBundle\Controller\DocumentationController" public="true">
|
||||
<argument type="service" id="nelmio_api_doc.generator" />
|
||||
<argument type="service" id="nelmio_api_doc.generator_locator" />
|
||||
</service>
|
||||
|
||||
<!-- Swagger Spec Generator -->
|
||||
<service id="nelmio_api_doc.generator" class="Nelmio\ApiDocBundle\ApiDocGenerator" public="true">
|
||||
<argument type="collection" /> <!-- Describers -->
|
||||
<argument type="collection" /> <!-- Model Describers -->
|
||||
</service>
|
||||
<service id="nelmio_api_doc.generator" alias="nelmio_api_doc.generator.default" />
|
||||
|
||||
<service id="nelmio_api_doc.controller_reflector" class="Nelmio\ApiDocBundle\Util\ControllerReflector" public="false">
|
||||
<argument type="service" id="service_container" />
|
||||
@ -32,14 +29,6 @@
|
||||
<tag name="nelmio_api_doc.describer" priority="1000" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.describers.route" class="Nelmio\ApiDocBundle\Describer\RouteDescriber" public="false">
|
||||
<argument type="service" id="nelmio_api_doc.routes" />
|
||||
<argument type="service" id="nelmio_api_doc.controller_reflector" />
|
||||
<argument type="collection" />
|
||||
|
||||
<tag name="nelmio_api_doc.describer" priority="-400" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.describers.default" class="Nelmio\ApiDocBundle\Describer\DefaultDescriber" public="false">
|
||||
<tag name="nelmio_api_doc.describer" priority="-1000" />
|
||||
</service>
|
||||
|
@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<service id="nelmio_api_doc.describers.swagger_php" class="Nelmio\ApiDocBundle\Describer\SwaggerPhpDescriber" public="false">
|
||||
<argument type="service" id="nelmio_api_doc.routes" />
|
||||
<argument type="service" id="nelmio_api_doc.controller_reflector" />
|
||||
<argument type="service" id="annotation_reader" />
|
||||
|
||||
<tag name="nelmio_api_doc.describer" priority="-200" />
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</container>
|
48
Resources/doc/areas.rst
Normal file
48
Resources/doc/areas.rst
Normal file
@ -0,0 +1,48 @@
|
||||
Areas
|
||||
=====
|
||||
|
||||
We've already seen that you can configure which routes are documented using ``nelmio_api_doc.areas``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
nelmio_api_doc:
|
||||
areas:
|
||||
path_patterns: [ ^/api ]
|
||||
|
||||
But in fact, this config option is way more powerful and allows you to split your documentation in several parts.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
You can define areas which will each generates a different documentation:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
nelmio_api_doc:
|
||||
areas:
|
||||
default:
|
||||
path_patterns: [ ^/api ]
|
||||
internal:
|
||||
path_patterns: [ ^/internal ]
|
||||
commercial:
|
||||
path_patterns: [ ^/commercial ]
|
||||
|
||||
Your main documentation is under the ``default`` area. It's the one shown when accessing ``/api/doc``.
|
||||
|
||||
Then update your routing to be able to access your different documentations:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# app/config/routing.yml
|
||||
app.swagger_ui:
|
||||
path: /api/doc/{area}
|
||||
methods: GET
|
||||
defaults: { _controller: nelmio_api_doc.controller.swagger_ui, area: default }
|
||||
|
||||
# To expose them as JSON
|
||||
#app.swagger.areas:
|
||||
# path: /api/doc/{area}.json
|
||||
# methods: GET
|
||||
# defaults: { _controller: nelmio_api_doc.controller.swagger }
|
||||
|
||||
That's all! You can now access ``/api/doc/internal`` and ``/api/doc/commercial``.
|
@ -1,6 +1,6 @@
|
||||
NelmioApiDocBundle
|
||||
==================
|
||||
|
||||
|
||||
The **NelmioApiDocBundle** bundle allows you to generate documentation in the
|
||||
OpenAPI (Swagger) format and provides a sandbox to interactively browse the API documentation.
|
||||
|
||||
@ -12,7 +12,7 @@ This bundle supports _Symfony_ route requirements, PHP annotations,
|
||||
[_FOSRestBundle_](https://github.com/FriendsOfSymfony/FOSRestBundle) annotations
|
||||
and apps using [_Api-Platform_](https://github.com/api-platform/api-platform).
|
||||
|
||||
For models, it supports the Symfony serializer and the JMS serializer.
|
||||
For models, it supports the Symfony serializer and the JMS serializer.
|
||||
|
||||
Migrate from 2.x to 3.0
|
||||
-----------------------
|
||||
@ -21,8 +21,8 @@ Migrate from 2.x to 3.0
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Open a command console, enter your project directory and execute the following command to download the latest version of this bundle:
|
||||
|
||||
Open a command console, enter your project directory and execute the following command to download the latest version of this bundle:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -65,7 +65,7 @@ Open a command console, enter your project directory and execute the following c
|
||||
path: /api/doc.json
|
||||
methods: GET
|
||||
defaults: { _controller: nelmio_api_doc.controller.swagger }
|
||||
|
||||
|
||||
As you just installed the bundle, you'll likely see routes you don't want in
|
||||
your documentation such as `/_profiler/`. To fix this, you can filter the
|
||||
routes that are documented by configuring the bundle:
|
||||
@ -79,7 +79,7 @@ Open a command console, enter your project directory and execute the following c
|
||||
- ^/api(?!/doc$)
|
||||
|
||||
How does this bundle work?
|
||||
--------------------------
|
||||
--------------------------
|
||||
|
||||
It generates you a swagger documentation from your symfony app thanks to
|
||||
_Describers_. Each of these _Describers_ extract infos from various sources.
|
||||
@ -88,11 +88,11 @@ routes, etc.
|
||||
|
||||
If you configured the ``app.swagger_ui`` route above, you can browse your
|
||||
documentation at `http://example.org/api/doc`.
|
||||
|
||||
|
||||
Using the bundle
|
||||
----------------
|
||||
|
||||
You can configure global information in the bundle configuration ``documentation.info`` section (take a look at
|
||||
You can configure global information in the bundle configuration ``documentation.info`` section (take a look at
|
||||
[the Swagger specification](http://swagger.io/specification/) to know the fields
|
||||
available):
|
||||
|
||||
@ -151,7 +151,7 @@ Use models
|
||||
|
||||
As shown in the example above, the bundle provides the ``@Model`` annotation.
|
||||
When you use it, the bundle will deduce your model properties.
|
||||
|
||||
|
||||
It has two options:
|
||||
|
||||
* ``type`` to specify your model's type::
|
||||
@ -165,12 +165,12 @@ It has two options:
|
||||
/**
|
||||
* @Model(type=User::class, groups={"non_sensitive_data"})
|
||||
*/
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
The ``@Model`` annotation acts like a ``@Schema`` annotation. If you nest it with a ``@Schema`` annotation, the bundle will consider that
|
||||
you're documenting an array of models.
|
||||
|
||||
|
||||
For instance, the following example::
|
||||
|
||||
/**
|
||||
@ -215,7 +215,7 @@ It has two options:
|
||||
public function myAction()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
If you're not using the JMS Serializer
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -240,3 +240,13 @@ support in your config:
|
||||
|
||||
nelmio_api_doc:
|
||||
models: { use_jms: false }
|
||||
|
||||
Learn more
|
||||
----------
|
||||
|
||||
If you need more complex features, take a look at:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
areas
|
||||
|
36
Tests/ApiDocGeneratorTest.php
Normal file
36
Tests/ApiDocGeneratorTest.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests;
|
||||
|
||||
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
||||
use Nelmio\ApiDocBundle\Describer\DefaultDescriber;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
|
||||
class ApiDocGeneratorTest extends TestCase
|
||||
{
|
||||
public function testCache()
|
||||
{
|
||||
$adapter = new ArrayAdapter();
|
||||
$generator = new ApiDocGenerator([new DefaultDescriber()], [], $adapter);
|
||||
|
||||
$this->assertEquals($generator->generate(), $adapter->getItem('swagger_doc')->get());
|
||||
}
|
||||
|
||||
public function testCacheWithCustomId()
|
||||
{
|
||||
$adapter = new ArrayAdapter();
|
||||
$generator = new ApiDocGenerator([new DefaultDescriber()], [], $adapter, 'custom_id');
|
||||
|
||||
$this->assertEquals($generator->generate(), $adapter->getItem('custom_id')->get());
|
||||
}
|
||||
}
|
41
Tests/Controller/ControllersTest.php
Normal file
41
Tests/Controller/ControllersTest.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Controller;
|
||||
|
||||
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
||||
use Nelmio\ApiDocBundle\Controller\DocumentationController;
|
||||
use Nelmio\ApiDocBundle\Controller\SwaggerUiController;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ControllersTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Providing an instance of "Nelmio\ApiDocBundle\ApiDocGenerator" to "Nelmio\ApiDocBundle\Controller\SwaggerUiController::__construct()" is deprecated since version 3.1. Provide it an instance of "Psr\Container\ContainerInterface" instead.
|
||||
*/
|
||||
public function testSwaggerUiControllerInstanciation()
|
||||
{
|
||||
$controller = new SwaggerUiController(new ApiDocGenerator([], []), $this->createMock('Twig_Environment'));
|
||||
$controller(new Request());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Providing an instance of "Nelmio\ApiDocBundle\ApiDocGenerator" to "Nelmio\ApiDocBundle\Controller\DocumentationController::__construct()" is deprecated since version 3.1. Provide it an instance of "Psr\Container\ContainerInterface" instead.
|
||||
*/
|
||||
public function testDocumentationControllerInstanciation()
|
||||
{
|
||||
$controller = new DocumentationController(new ApiDocGenerator([], []));
|
||||
$controller(new Request());
|
||||
}
|
||||
}
|
62
Tests/DependencyInjection/ConfigurationTest.php
Normal file
62
Tests/DependencyInjection/ConfigurationTest.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\DependencyInjection;
|
||||
|
||||
use Nelmio\ApiDocBundle\DependencyInjection\Configuration;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
|
||||
class ConfigurationTest extends TestCase
|
||||
{
|
||||
public function testDefaultArea()
|
||||
{
|
||||
$processor = new Processor();
|
||||
$config = $processor->processConfiguration(new Configuration(), [['areas' => ['path_patterns' => ['/foo']]]]);
|
||||
|
||||
$this->assertEquals(['default' => ['path_patterns' => ['/foo']]], $config['areas']);
|
||||
}
|
||||
|
||||
public function testAreas()
|
||||
{
|
||||
$processor = new Processor();
|
||||
$config = $processor->processConfiguration(new Configuration(), [['areas' => $areas = [
|
||||
'default' => ['path_patterns' => ['/foo']],
|
||||
'internal' => ['path_patterns' => ['/internal']],
|
||||
'commercial' => ['path_patterns' => ['/internal']],
|
||||
]]]);
|
||||
|
||||
$this->assertEquals($areas, $config['areas']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage You must not use both `nelmio_api_doc.areas` and `nelmio_api_doc.routes` config options. Please update your config to only use `nelmio_api_doc.areas`.
|
||||
*/
|
||||
public function testBothAreasAndRoutes()
|
||||
{
|
||||
$processor = new Processor();
|
||||
$config = $processor->processConfiguration(new Configuration(), [['areas' => [], 'routes' => []]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation The `nelmio_api_doc.routes` config option is deprecated. Please use `nelmio_api_doc.areas` instead (just replace `routes` by `areas` in your config).
|
||||
*/
|
||||
public function testDefaultConfig()
|
||||
{
|
||||
$processor = new Processor();
|
||||
$config = $processor->processConfiguration(new Configuration(), [['routes' => ['path_patterns' => ['/foo']]]]);
|
||||
|
||||
$this->assertEquals(['default' => ['path_patterns' => ['/foo']]], $config['areas']);
|
||||
}
|
||||
}
|
32
Tests/Functional/Controller/TestController.php
Normal file
32
Tests/Functional/Controller/TestController.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioApiDocBundle package.
|
||||
*
|
||||
* (c) Nelmio
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Functional\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Swagger\Annotations as SWG;
|
||||
|
||||
/**
|
||||
* @Route("/test")
|
||||
*/
|
||||
class TestController
|
||||
{
|
||||
/**
|
||||
* @SWG\Response(
|
||||
* response="200",
|
||||
* description="Test"
|
||||
* )
|
||||
* @Route("/test/", methods={"GET"})
|
||||
*/
|
||||
public function testAction()
|
||||
{
|
||||
}
|
||||
}
|
@ -18,19 +18,40 @@ class SwaggerUiTest extends WebTestCase
|
||||
return parent::createClient([], ['PHP_SELF' => '/app_dev.php/docs', 'SCRIPT_FILENAME' => '/var/www/app/web/app_dev.php']);
|
||||
}
|
||||
|
||||
public function testSwaggerUi()
|
||||
/**
|
||||
* @dataProvider areaProvider
|
||||
*/
|
||||
public function testSwaggerUi($url, $area, $expected)
|
||||
{
|
||||
$client = self::createClient();
|
||||
$crawler = $client->request('GET', '/app_dev.php/docs/');
|
||||
$crawler = $client->request('GET', '/app_dev.php'.$url);
|
||||
|
||||
$response = $client->getResponse();
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type'));
|
||||
|
||||
$this->assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']);
|
||||
}
|
||||
|
||||
public function areaProvider()
|
||||
{
|
||||
$expected = $this->getSwaggerDefinition()->toArray();
|
||||
$expected['basePath'] = '/app_dev.php';
|
||||
|
||||
$this->assertEquals($expected, json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true)['spec']);
|
||||
yield ['/docs', 'default', $expected];
|
||||
|
||||
// Api-platform documentation
|
||||
$expected['paths'] = [
|
||||
'/api/dummies' => $expected['paths']['/api/dummies'],
|
||||
'/api/foo' => $expected['paths']['/api/foo'],
|
||||
'/api/dummies/{id}' => $expected['paths']['/api/dummies/{id}'],
|
||||
'/test/test/' => ['get' => [
|
||||
'responses' => ['200' => ['description' => 'Test']],
|
||||
]],
|
||||
];
|
||||
$expected['definitions'] = ['Dummy' => $expected['definitions']['Dummy']];
|
||||
|
||||
yield ['/docs/test', 'test', $expected];
|
||||
}
|
||||
|
||||
public function testJsonDocs()
|
||||
|
@ -64,11 +64,11 @@ class TestKernel extends Kernel
|
||||
*/
|
||||
protected function configureRoutes(RouteCollectionBuilder $routes)
|
||||
{
|
||||
$routes->import(__DIR__.'/Controller/TestController.php', '/', 'annotation');
|
||||
$routes->import(__DIR__.'/Controller/ApiController.php', '/', 'annotation');
|
||||
$routes->import(__DIR__.'/Controller/UndocumentedController.php', '/', 'annotation');
|
||||
$routes->import('', '/api', 'api_platform');
|
||||
$routes->import('@NelmioApiDocBundle/Resources/config/routing/swaggerui.xml', '/docs');
|
||||
|
||||
$routes->add('/docs/{area}', 'nelmio_api_doc.controller.swagger_ui')->setDefault('area', 'default');
|
||||
$routes->add('/docs.json', 'nelmio_api_doc.controller.swagger');
|
||||
|
||||
if ($this->useJMS) {
|
||||
@ -110,8 +110,9 @@ class TestKernel extends Kernel
|
||||
'title' => 'My Test App',
|
||||
],
|
||||
],
|
||||
'routes' => [
|
||||
'path_patterns' => ['^/api(?!/admin)'],
|
||||
'areas' => [
|
||||
'default' => ['path_patterns' => ['^/api(?!/admin)']],
|
||||
'test' => ['path_patterns' => ['^/test']],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user