mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 23:59:26 +03:00
Merge pull request #1026 from nelmio/doccontroller
Add a controller exposing the documentation in json
This commit is contained in:
commit
7690f6cfb5
@ -18,8 +18,7 @@ use Swagger\Annotations\AbstractAnnotation;
|
||||
*/
|
||||
final class Model extends AbstractAnnotation
|
||||
{
|
||||
|
||||
/** @inheritdoc */
|
||||
/** {@inheritdoc} */
|
||||
public static $_types = [
|
||||
'type' => 'string',
|
||||
'groups' => '[string]',
|
||||
|
30
Controller/DocumentationController.php
Normal file
30
Controller/DocumentationController.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?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\Controller;
|
||||
|
||||
use Nelmio\ApiDocBundle\ApiDocGenerator;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
final class DocumentationController
|
||||
{
|
||||
private $apiDocGenerator;
|
||||
|
||||
public function __construct(ApiDocGenerator $apiDocGenerator)
|
||||
{
|
||||
$this->apiDocGenerator = $apiDocGenerator;
|
||||
}
|
||||
|
||||
public function __invoke()
|
||||
{
|
||||
return new JsonResponse($this->apiDocGenerator->generate()->toArray());
|
||||
}
|
||||
}
|
@ -12,18 +12,18 @@
|
||||
namespace Nelmio\ApiDocBundle\DependencyInjection;
|
||||
|
||||
use FOS\RestBundle\Controller\Annotations\ParamInterface;
|
||||
use Nelmio\ApiDocBundle\ModelDescriber\FormModelDescriber;
|
||||
use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder;
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder;
|
||||
use Nelmio\ApiDocBundle\ModelDescriber\FormModelDescriber;
|
||||
|
||||
final class NelmioApiDocExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
@ -65,8 +65,8 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
|
||||
->setFactory([
|
||||
(new Definition(FilteredRouteCollectionBuilder::class))
|
||||
->addArgument($config['routes']['path_patterns']),
|
||||
'filter']
|
||||
)
|
||||
'filter',
|
||||
])
|
||||
->addArgument($routesDefinition);
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,9 @@ use Nelmio\ApiDocBundle\SwaggerPhp\AddDefaults;
|
||||
use Nelmio\ApiDocBundle\SwaggerPhp\ModelRegister;
|
||||
use Nelmio\ApiDocBundle\Util\ControllerReflector;
|
||||
use Swagger\Analysis;
|
||||
use Swagger\Annotations\AbstractAnnotation;
|
||||
use Swagger\Annotations as SWG;
|
||||
use Swagger\Context;
|
||||
use Swagger\Annotations\AbstractAnnotation;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelRegistryAwareInterface
|
||||
@ -175,7 +175,8 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg
|
||||
return $path;
|
||||
}
|
||||
|
||||
private function updateNestedAnnotations($value, Context $context) {
|
||||
private function updateNestedAnnotations($value, Context $context)
|
||||
{
|
||||
if ($value instanceof AbstractAnnotation) {
|
||||
$value->_context = $context;
|
||||
} elseif (!is_array($value)) {
|
||||
|
27
README.md
27
README.md
@ -39,31 +39,40 @@ class AppKernel extends Kernel
|
||||
}
|
||||
```
|
||||
|
||||
To access your documentation in your browser, register the following route:
|
||||
To browse your documentation with Swagger UI, register the following route:
|
||||
|
||||
```yml
|
||||
# app/config/routing.yml
|
||||
NelmioApiDocBundle:
|
||||
app.swagger_ui:
|
||||
resource: "@NelmioApiDocBundle/Resources/config/routing/swaggerui.xml"
|
||||
prefix: /api/doc
|
||||
```
|
||||
|
||||
If you also want to expose it in JSON, register this route:
|
||||
|
||||
```yml
|
||||
# app/config/routing.yml
|
||||
app.swagger:
|
||||
path: /api/doc.json
|
||||
methods: GET
|
||||
defaults: { _controller: nelmio_api_doc.controller.swagger }
|
||||
```
|
||||
|
||||
## What does this bundle?
|
||||
|
||||
It generates you a swagger documentation from your symfony app thanks to
|
||||
_Describers_. Each of this _Describers_ extract infos from various sources.
|
||||
_Describers_. Each of these _Describers_ extract infos from various sources.
|
||||
For instance, one extract data from SwaggerPHP annotations, one from your
|
||||
routes, etc.
|
||||
|
||||
If you configured the route above, you can browse your documentation at
|
||||
`http://example.org/api/doc`.
|
||||
If you configured the ``app.swagger_ui`` route above, you can browse your
|
||||
documentation at `http://example.org/api/doc`.
|
||||
|
||||
## Configure the bundle
|
||||
|
||||
If 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:
|
||||
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:
|
||||
|
||||
```yml
|
||||
# app/config/config.yml
|
||||
|
@ -4,12 +4,16 @@
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<!-- Swagger Ui Controller -->
|
||||
<!-- Controllers -->
|
||||
<service id="nelmio_api_doc.controller.swagger_ui" class="Nelmio\ApiDocBundle\Controller\SwaggerUiController">
|
||||
<argument type="service" id="nelmio_api_doc.generator" />
|
||||
<argument type="service" id="twig" />
|
||||
</service>
|
||||
|
||||
<service id="nelmio_api_doc.controller.swagger" class="Nelmio\ApiDocBundle\Controller\DocumentationController">
|
||||
<argument type="service" id="nelmio_api_doc.generator" />
|
||||
</service>
|
||||
|
||||
<!-- Swagger Spec Generator -->
|
||||
<service id="nelmio_api_doc.generator" class="Nelmio\ApiDocBundle\ApiDocGenerator">
|
||||
<argument type="collection" /> <!-- Describers -->
|
||||
|
@ -70,7 +70,6 @@ final class ModelRegister
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$annotation->merge([new $annotationClass([
|
||||
'ref' => $this->modelRegistry->register(new Model($this->createType($model->type), $model->groups)),
|
||||
])]);
|
||||
|
@ -15,8 +15,8 @@ use FOS\RestBundle\Controller\Annotations\QueryParam;
|
||||
use FOS\RestBundle\Controller\Annotations\RequestParam;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\User;
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\Article;
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\Entity\User;
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyType;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Swagger\Annotations as SWG;
|
||||
@ -134,6 +134,5 @@ class ApiController
|
||||
*/
|
||||
public function formAction()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,19 @@
|
||||
<?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\Form;
|
||||
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Swagger\Annotations\Definition;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class DummyType extends AbstractType
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace Nelmio\ApiDocBundle\Tests\Functional;
|
||||
|
||||
use EXSyst\Component\Swagger\Operation;
|
||||
use EXSyst\Component\Swagger\Schema;
|
||||
use EXSyst\Component\Swagger\Tag;
|
||||
|
||||
class FunctionalTest extends WebTestCase
|
||||
@ -178,37 +177,9 @@ class FunctionalTest extends WebTestCase
|
||||
'foo' => [
|
||||
'type' => 'string',
|
||||
'enum' => ['male', 'female'],
|
||||
]
|
||||
],
|
||||
],
|
||||
'required' => ['foo'],
|
||||
], $this->getModel('DummyType')->toArray());
|
||||
}
|
||||
|
||||
private function getSwaggerDefinition()
|
||||
{
|
||||
static::createClient();
|
||||
|
||||
return static::$kernel->getContainer()->get('nelmio_api_doc.generator')->generate();
|
||||
}
|
||||
|
||||
private function getModel($name): Schema
|
||||
{
|
||||
$definitions = $this->getSwaggerDefinition()->getDefinitions();
|
||||
$this->assertTrue($definitions->has($name));
|
||||
|
||||
return $definitions->get($name);
|
||||
}
|
||||
|
||||
private function getOperation($path, $method): Operation
|
||||
{
|
||||
$api = $this->getSwaggerDefinition();
|
||||
$paths = $api->getPaths();
|
||||
|
||||
$this->assertTrue($paths->has($path), sprintf('Path "%s" does not exist.', $path));
|
||||
$action = $paths->get($path);
|
||||
|
||||
$this->assertTrue($action->hasOperation($method), sprintf('Operation "%s" for path "%s" does not exist', $path, $method));
|
||||
|
||||
return $action->getOperation($method);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,18 @@ class SwaggerUiTest extends WebTestCase
|
||||
$this->assertEquals('text/html; charset=UTF-8', $response->headers->get('Content-Type'));
|
||||
|
||||
$swaggerUiSpec = json_decode($crawler->filterXPath('//script[@id="swagger-data"]')->text(), true);
|
||||
$appSpec = $client->getContainer()->get('nelmio_api_doc.generator')->generate()->toArray();
|
||||
$this->assertEquals($appSpec, $swaggerUiSpec['spec']);
|
||||
$this->assertEquals($this->getSwaggerDefinition()->toArray(), $swaggerUiSpec['spec']);
|
||||
}
|
||||
|
||||
public function testJsonDocs()
|
||||
{
|
||||
$client = self::createClient();
|
||||
$crawler = $client->request('GET', '/docs.json');
|
||||
|
||||
$response = $client->getResponse();
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertEquals('application/json', $response->headers->get('Content-Type'));
|
||||
|
||||
$this->assertEquals($this->getSwaggerDefinition()->toArray(), json_decode($response->getContent(), true));
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ namespace Nelmio\ApiDocBundle\Tests\Functional;
|
||||
use ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle;
|
||||
use FOS\RestBundle\FOSRestBundle;
|
||||
use Nelmio\ApiDocBundle\NelmioApiDocBundle;
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\TestBundle;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
@ -52,6 +51,8 @@ class TestKernel extends Kernel
|
||||
$routes->import(__DIR__.'/Controller/', '/', 'annotation');
|
||||
$routes->import('', '/api', 'api_platform');
|
||||
$routes->import('@NelmioApiDocBundle/Resources/config/routing/swaggerui.xml', '/docs');
|
||||
|
||||
$routes->add('/docs.json', 'nelmio_api_doc.controller.swagger');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,7 +77,7 @@ class TestKernel extends Kernel
|
||||
[
|
||||
'path' => '^/',
|
||||
'fallback_format' => 'json',
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
@ -11,8 +11,8 @@
|
||||
|
||||
namespace Nelmio\ApiDocBundle\Tests\Functional;
|
||||
|
||||
|
||||
use Nelmio\ApiDocBundle\Tests\Functional\TestKernel;
|
||||
use EXSyst\Component\Swagger\Operation;
|
||||
use EXSyst\Component\Swagger\Schema;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
|
||||
|
||||
class WebTestCase extends BaseWebTestCase
|
||||
@ -24,4 +24,32 @@ class WebTestCase extends BaseWebTestCase
|
||||
{
|
||||
return TestKernel::class;
|
||||
}
|
||||
|
||||
protected function getSwaggerDefinition()
|
||||
{
|
||||
static::createClient();
|
||||
|
||||
return static::$kernel->getContainer()->get('nelmio_api_doc.generator')->generate();
|
||||
}
|
||||
|
||||
protected function getModel($name): Schema
|
||||
{
|
||||
$definitions = $this->getSwaggerDefinition()->getDefinitions();
|
||||
$this->assertTrue($definitions->has($name));
|
||||
|
||||
return $definitions->get($name);
|
||||
}
|
||||
|
||||
protected function getOperation($path, $method): Operation
|
||||
{
|
||||
$api = $this->getSwaggerDefinition();
|
||||
$paths = $api->getPaths();
|
||||
|
||||
$this->assertTrue($paths->has($path), sprintf('Path "%s" does not exist.', $path));
|
||||
$action = $paths->get($path);
|
||||
|
||||
$this->assertTrue($action->hasOperation($method), sprintf('Operation "%s" for path "%s" does not exist', $path, $method));
|
||||
|
||||
return $action->getOperation($method);
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,9 @@ namespace Nelmio\ApiDocBundle\Tests\Model;
|
||||
|
||||
use EXSyst\Component\Swagger\Schema;
|
||||
use EXSyst\Component\Swagger\Swagger;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Nelmio\ApiDocBundle\Model\Model;
|
||||
use Nelmio\ApiDocBundle\Model\ModelRegistry;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
|
||||
class ModelRegistryTest extends TestCase
|
||||
|
@ -12,12 +12,12 @@
|
||||
namespace Nelmio\ApiDocBundle\Tests\Routing;
|
||||
|
||||
use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for FilteredRouteCollectionBuilder class
|
||||
* Tests for FilteredRouteCollectionBuilder class.
|
||||
*/
|
||||
class FilteredRouteCollectionBuilderTest extends TestCase
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user