Doc generation for the specific API version

This commit is contained in:
Vitaliy Chesnokov 2019-04-24 12:55:08 +03:00
parent f0a606b636
commit 1c4f003e76
No known key found for this signature in database
GPG Key ID: FD23DF1B48ECC3EB
13 changed files with 144 additions and 10 deletions

View File

@ -34,6 +34,7 @@ class DumpCommand extends ContainerAwareCommand
'Output format like: ' . implode(', ', $this->availableFormats), 'Output format like: ' . implode(', ', $this->availableFormats),
$this->availableFormats[0] $this->availableFormats[0]
) )
->addOption('api-version', null, InputOption::VALUE_REQUIRED, 'The API version')
->addOption('view', '', InputOption::VALUE_OPTIONAL, '', ApiDoc::DEFAULT_VIEW) ->addOption('view', '', InputOption::VALUE_OPTIONAL, '', ApiDoc::DEFAULT_VIEW)
->addOption('no-sandbox', '', InputOption::VALUE_NONE) ->addOption('no-sandbox', '', InputOption::VALUE_NONE)
->setName('api:doc:dump') ->setName('api:doc:dump')
@ -66,7 +67,11 @@ class DumpCommand extends ContainerAwareCommand
$this->getContainer()->set('request', new Request(), 'request'); $this->getContainer()->set('request', new Request(), 'request');
} }
$extractedDoc = $this->getContainer()->get('nelmio_api_doc.extractor.api_doc_extractor')->all($view); $extractor = $this->getContainer()->get('nelmio_api_doc.extractor.api_doc_extractor');
$extractedDoc = $input->hasOption('api-version') ?
$extractor->allForVersion($input->getOption('api-version'), $view) :
$extractor->all($view);
$formattedDoc = $formatter->format($extractedDoc); $formattedDoc = $formatter->format($extractedDoc);
if ('json' === $format) { if ('json' === $format) {

View File

@ -20,9 +20,11 @@ use Symfony\Component\HttpFoundation\Response;
class ApiDocController extends Controller class ApiDocController extends Controller
{ {
public function indexAction($view = ApiDoc::DEFAULT_VIEW) public function indexAction(Request $request, $view = ApiDoc::DEFAULT_VIEW)
{ {
$extractedDoc = $this->get('nelmio_api_doc.extractor.api_doc_extractor')->all($view); $extractor = $this->get('nelmio_api_doc.extractor.api_doc_extractor');
$apiVersion = $request->query->get('_version', null);
$extractedDoc = $apiVersion ? $extractor->allForVersion($apiVersion, $view) : $extractor->all($view);
$htmlContent = $this->get('nelmio_api_doc.formatter.html_formatter')->format($extractedDoc); $htmlContent = $this->get('nelmio_api_doc.formatter.html_formatter')->format($extractedDoc);
return new Response($htmlContent, 200, array('Content-Type' => 'text/html')); return new Response($htmlContent, 200, array('Content-Type' => 'text/html'));

View File

@ -101,6 +101,29 @@ class ApiDocExtractor
return $this->extractAnnotations($this->getRoutes(), $view); return $this->extractAnnotations($this->getRoutes(), $view);
} }
/**
* Extracts annotations from routes for specific version
*
* @param string $apiVersion API version
* @param string $view
*
* @return array
*/
public function allForVersion($apiVersion, $view = ApiDoc::DEFAULT_VIEW)
{
$data = $this->all($view);
foreach ($data as $k => $a) {
// ignore other api version's routes
if (
$a['annotation']->getRoute()->getDefault('_version') &&
!version_compare($apiVersion, $a['annotation']->getRoute()->getDefault('_version'), '=')
) {
unset($data[$k]);
}
}
return $data;
}
/** /**
* Returns an array of data where each data is an array with the following keys: * Returns an array of data where each data is an array with the following keys:
* - annotation * - annotation

View File

@ -119,3 +119,26 @@ By calling an URL with the parameter ``?_doc=1``, you will get the corresponding
documentation if available. documentation if available.
.. _`installation chapter`: https://getcomposer.org/doc/00-intro.md .. _`installation chapter`: https://getcomposer.org/doc/00-intro.md
Route versions
~~~~~~~~~~~~~~
You can define version for the API routes:
.. code-block:: yaml
api_v3_products_list:
pattern: /api/v3/products.{_format}
defaults: { _controller: NelmioApiDocTestBundle:Test:routeVersion, _format: json, _version: "3.0" }
requirements:
_method: GET
api_v1_orders:
resource: "@AcmeOrderBundle/Resources/config/routing/orders_v1.yml"
defaults: { _version: "1.0" }
prefix: /api/v1/orders
And generate documentation for specific version by the command:
.. code-block:: bash
php app/console api:doc:dump --format=html --api-version=3.0 > api.html
Or by adding `?_version={version}` to API documentation page URL.

View File

@ -19,7 +19,7 @@ class ApiDocExtractorTest extends WebTestCase
{ {
const NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE = 5; const NB_ROUTES_ADDED_BY_DUNGLAS_API_BUNDLE = 5;
private static $ROUTES_QUANTITY_DEFAULT = 34; // Routes in the default view private static $ROUTES_QUANTITY_DEFAULT = 35; // Routes in the default view
private static $ROUTES_QUANTITY_PREMIUM = 6; // Routes in the premium view private static $ROUTES_QUANTITY_PREMIUM = 6; // Routes in the premium view
private static $ROUTES_QUANTITY_TEST = 2; // Routes in the test view private static $ROUTES_QUANTITY_TEST = 2; // Routes in the test view
@ -96,6 +96,18 @@ class ApiDocExtractorTest extends WebTestCase
$this->assertEquals('test.dev|test.com', $a5requirements['domain']['requirement']); $this->assertEquals('test.dev|test.com', $a5requirements['domain']['requirement']);
} }
public function testRouteVersionChecking()
{
$container = $this->getContainer();
$extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor');
$data = $extractor->allForVersion('1.5');
$this->assertTrue(is_array($data));
$this->assertCount(self::$ROUTES_QUANTITY_DEFAULT, $data);
$data = $extractor->allForVersion('1.4');
$this->assertTrue(is_array($data));
$this->assertCount(self::$ROUTES_QUANTITY_DEFAULT - 1, $data);
}
public function testGet() public function testGet()
{ {
$container = $this->getContainer(); $container = $this->getContainer();

View File

@ -84,6 +84,13 @@ class TestController
{ {
} }
/**
* @ApiDoc()
*/
public function routeVersionAction()
{
}
/** /**
* @ApiDoc(description="Action without HTTP verb") * @ApiDoc(description="Action without HTTP verb")
*/ */

View File

@ -253,3 +253,9 @@ test_route_31:
path: /z-query-requirement-param-not-set path: /z-query-requirement-param-not-set
methods: [GET] methods: [GET]
defaults: { _controller: NelmioApiDocTestBundle:Test:zActionWithRequirementParamNotSet } defaults: { _controller: NelmioApiDocTestBundle:Test:zActionWithRequirementParamNotSet }
test_route_version_checking:
path: /zz-tests-route-version.{_format}
methods: [GET]
defaults: { _controller: NelmioApiDocTestBundle:Test:routeVersion, _format: json, _version: "1.5" }

View File

@ -933,3 +933,12 @@ related[b]:
### `POST` /zsecured ### ### `POST` /zsecured ###
### `GET` /zz-tests-route-version.{_format} ###
#### Requirements ####
**_format**

View File

@ -2316,5 +2316,20 @@ With multiple lines.',
), ),
'deprecated' => false, 'deprecated' => false,
), ),
22 => array(
'method' => 'GET',
'uri' => '/zz-tests-route-version.{_format}',
'requirements' => array(
'_format' => array(
'requirement' => '',
'dataType' => '',
'description' => '',
),
),
'https' => false,
'authentication' => false,
'authenticationRoles' => array(),
'deprecated' => false,
),
), ),
); );

View File

@ -1017,3 +1017,12 @@ related[b]:
### `POST` /zsecured ### ### `POST` /zsecured ###
### `GET` /zz-tests-route-version.{_format} ###
#### Requirements ####
**_format**

View File

@ -2470,5 +2470,23 @@ With multiple lines.',
), ),
'deprecated' => false, 'deprecated' => false,
), ),
27 =>
array(
'authentication' => false,
'method' => 'GET',
'uri' => '/zz-tests-route-version.{_format}',
'https' => false,
'authenticationRoles' => array(),
'deprecated' => false,
'requirements' =>
array(
'_format' =>
array(
'requirement' => '',
'dataType' => '',
'description' => '',
),
),
),
), ),
); );

View File

@ -25,7 +25,7 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase
*/ */
public function testParserWithNestedType($type) public function testParserWithNestedType($type)
{ {
$metadataFactory = $this->getMock('Metadata\MetadataFactoryInterface'); $metadataFactory = $this->createMock('Metadata\MetadataFactoryInterface');
$docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor') $docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
@ -56,7 +56,7 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase
$metadata->addPropertyMetadata($propertyMetadataBar); $metadata->addPropertyMetadata($propertyMetadataBar);
$metadata->addPropertyMetadata($propertyMetadataBaz); $metadata->addPropertyMetadata($propertyMetadataBaz);
$propertyNamingStrategy = $this->getMock('JMS\Serializer\Naming\PropertyNamingStrategyInterface'); $propertyNamingStrategy = $this->createMock('JMS\Serializer\Naming\PropertyNamingStrategyInterface');
$propertyNamingStrategy $propertyNamingStrategy
->expects($this->at(0)) ->expects($this->at(0))
@ -131,7 +131,7 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase
public function testParserWithGroups() public function testParserWithGroups()
{ {
$metadataFactory = $this->getMock('Metadata\MetadataFactoryInterface'); $metadataFactory = $this->createMock('Metadata\MetadataFactoryInterface');
$docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor') $docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
@ -332,7 +332,7 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase
public function testNestedGroups() public function testNestedGroups()
{ {
$metadataFactory = $this->getMock('Metadata\MetadataFactoryInterface'); $metadataFactory = $this->createMock('Metadata\MetadataFactoryInterface');
$docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor') $docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
@ -419,7 +419,7 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase
public function testParserWithVersion() public function testParserWithVersion()
{ {
$metadataFactory = $this->getMock('Metadata\MetadataFactoryInterface'); $metadataFactory = $this->createMock('Metadata\MetadataFactoryInterface');
$docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor') $docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();
@ -501,7 +501,7 @@ class JmsMetadataParserTest extends \PHPUnit_Framework_TestCase
public function testParserWithInline() public function testParserWithInline()
{ {
$metadataFactory = $this->getMock('Metadata\MetadataFactoryInterface'); $metadataFactory = $this->createMock('Metadata\MetadataFactoryInterface');
$docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor') $docCommentExtractor = $this->getMockBuilder('Nelmio\ApiDocBundle\Util\DocCommentExtractor')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock();

View File

@ -12,6 +12,7 @@
namespace Nelmio\ApiDocBundle\Tests; namespace Nelmio\ApiDocBundle\Tests;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\Kernel;
abstract class WebTestCase extends BaseWebTestCase abstract class WebTestCase extends BaseWebTestCase
@ -36,6 +37,10 @@ abstract class WebTestCase extends BaseWebTestCase
return \PHPUnit_Util_ErrorHandler::handleError($errorNumber, $message, $file, $line); return \PHPUnit_Util_ErrorHandler::handleError($errorNumber, $message, $file, $line);
} }
/**
* @param array $options
* @return ContainerInterface
*/
protected function getContainer(array $options = array()) protected function getContainer(array $options = array())
{ {
if (!static::$kernel) { if (!static::$kernel) {