From ea41c41c7c811e43d9f631b57d5f9274cdd53995 Mon Sep 17 00:00:00 2001 From: Bez Hermoso Date: Thu, 31 Jul 2014 12:00:56 -0700 Subject: [PATCH 1/2] Swagger command updates. --- Command/SwaggerDumpCommand.php | 163 +++++++++++++++++++++------------ 1 file changed, 103 insertions(+), 60 deletions(-) diff --git a/Command/SwaggerDumpCommand.php b/Command/SwaggerDumpCommand.php index 6b9e93d..2a661ab 100644 --- a/Command/SwaggerDumpCommand.php +++ b/Command/SwaggerDumpCommand.php @@ -26,107 +26,150 @@ use Symfony\Component\Filesystem\Filesystem; */ class SwaggerDumpCommand extends ContainerAwareCommand { + /** + * @var Filesystem + */ + protected $filesystem; + + protected $destination; + protected function configure() { + $this->filesystem = new Filesystem(); + $this ->setDescription('Dump Swagger-compliant JSON files.') ->addOption('resource', '', InputOption::VALUE_OPTIONAL, 'A specific resource API declaration to dump.') - ->addOption('all', '', InputOption::VALUE_NONE, 'Dump resource list and all API declarations.') ->addOption('list-only', '', InputOption::VALUE_NONE, 'Dump resource list only.') - ->addArgument('destination', InputOption::VALUE_REQUIRED, 'Directory to dump JSON files in.', null) + ->addArgument('destination', InputOption::VALUE_OPTIONAL, 'Directory to dump JSON files in.', null) ->setName('api:swagger:dump'); } protected function execute(InputInterface $input, OutputInterface $output) { $container = $this->getContainer(); + + $extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor'); + $destination = $input->getArgument('destination'); - $rootDir = $container->get('kernel')->getRootDir(); - $rootDir = $rootDir . '/..'; + if (count($destination) > 0) { - if (null === $destination) { - $destination = realpath($rootDir . '/' . $destination); - } + $destination = $destination[0]; - $fs = new Filesystem(); + $realpath = realpath($destination); - if (!$fs->exists($destination)) { - $fs->mkdir($destination); - } - - $destination = realpath($destination); - - if ($input->getOption('all') && $input->getOption('resource')) { - throw new \RuntimeException('Cannot selectively dump a resource with the --all flag.'); + if ($realpath == false) { + $rootDir = $container->getParameter('kernel.root_dir'); + $rootDir = realpath($rootDir . '/..'); + $destination = $rootDir . '/' . $destination; + } else { + $destination = $realpath; + } + $this->destination = $destination; + } else { + $this->destination = null; } if ($input->getOption('list-only') && $input->getOption('resource')) { throw new \RuntimeException('Cannot selectively dump a resource with the --list-only flag.'); } - if ($input->getOption('all') && $input->getOption('list-only')) { - throw new \RuntimeException('Cannot selectively dump resource list with the --all flag.'); - } - - $output->writeln(''); - $output->writeln('Reading annotations...'); - $extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor'); - $data = $extractor->all(); + $apiDocs = $extractor->all(); if ($input->getOption('list-only')) { - $this->dumpResourceList($destination, $data, $output); + $data = $this->getResourceList($apiDocs, $output); + $this->dump($data, null, $input, $output); + return; } if (false != ($resource = $input->getOption('resource'))) { - $this->dumpApiDeclaration($destination, $data, $resource, $output); - } - - if ($input->getOption('all')) { - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); - $this->dumpResourceList($destination, $data, $output); - $list = $formatter->format($data); - foreach ($list['apis'] as $api) { - $this->dumpApiDeclaration($destination, $data, substr($api['path'], 1), $output); + $data = $this->getApiDeclaration($apiDocs, $resource, $output); + if (count($data['apis']) === 0) { + throw new \InvalidArgumentException(sprintf('Resource "%s" does not exist.', $resource)); } + $this->dump($data, $resource, $input, $output); + return; + } + + $data = $this->getResourceList($apiDocs); + + if ($this->destination == null) { + $output->writeln(''); + $output->writeln('Resource list: '); + } + + $this->dump($data, null, $input, $output, false); + + foreach ($data['apis'] as $api) { + + $resource = substr($api['path'], 1); + if ($this->destination == null) { + $output->writeln(''); + $output->writeln(sprintf('API declaration for "%s" resource: ', $resource)); + } + $data = $this->getApiDeclaration($apiDocs, $resource, $output); + $this->dump($data, $resource, $input, $output, false); } } - protected function dumpResourceList($destination, array $data, OutputInterface $output) + protected function dump(array $data, $resource, InputInterface $input, OutputInterface $output, $treatAsFile = true) { - $container = $this->getContainer(); - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); - $list = $formatter->format($data); + $content = json_encode($data, JSON_PRETTY_PRINT); - $fs = new Filesystem(); - $path = $destination . '/api-docs.json'; - - $string = sprintf('Dump resource list to %s: ', $path); - try { - $fs->dumpFile($path, json_encode($list)); - } catch (IOException $e) { - $output->writeln($string . ' NOT OK'); + if ($this->destination == null) { + $output->writeln($content); + return; } - $output->writeln($string . 'OK'); - } - protected function dumpApiDeclaration($destination, array $data, $resource, OutputInterface $output) - { - $container = $this->getContainer(); - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); - - $list = $formatter->format($data, '/' . $resource); - - $fs = new Filesystem(); - $path = sprintf($destination . '/%s.json', $resource); + if ($resource == false) { + if ($treatAsFile === false) { + $path = sprintf('%s/api-docs.json', $this->destination); + } else { + $path = $this->destination; + } + $string = sprintf('Dumping resource list to %s: ', $path); + $this->writeToFile($data, $path, $output, $string); + return; + } + if ($treatAsFile === false) { + $path = sprintf('%s/%s.json', $this->destination, $resource); + } else { + $path = $this->destination; + } $string = sprintf('Dump API declaration to %s: ', $path); + $this->writeToFile($content, $path, $output, $string); + + } + + protected function writeToFile($content, $file, OutputInterface $output, $string = null) + { + $message = array($string); try { - $fs->dumpFile($path, json_encode($list)); + $this->filesystem->dumpFile($file, $content); + $message[] = 'OK'; + $output->writeln(implode(' ', array_filter($message))); } catch (IOException $e) { - $output->writeln($string . ' NOT OK'); + $message[] = 'NOT OK'; + $output->writeln(implode(' ', array_filter($message))); } - $output->writeln($string . 'OK'); + } + + protected function getResourceList(array $data) + { + $container = $this->getContainer(); + $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); + $list = $formatter->format($data); + return $list; + } + + protected function getApiDeclaration(array $data, $resource) + { + $container = $this->getContainer(); + $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); + $list = $formatter->format($data, '/' . $resource); + return $list; } } \ No newline at end of file From 0e01a00aaf5c25480144c0ff5f06f173fa640300 Mon Sep 17 00:00:00 2001 From: Bez Hermoso Date: Thu, 31 Jul 2014 12:27:40 -0700 Subject: [PATCH 2/2] Behavior and usage updates. --- Command/SwaggerDumpCommand.php | 104 ++++++++++++++----------------- Resources/doc/swagger-support.md | 6 +- 2 files changed, 49 insertions(+), 61 deletions(-) diff --git a/Command/SwaggerDumpCommand.php b/Command/SwaggerDumpCommand.php index 2a661ab..f5c0704 100644 --- a/Command/SwaggerDumpCommand.php +++ b/Command/SwaggerDumpCommand.php @@ -11,16 +11,17 @@ namespace Nelmio\ApiDocBundle\Command; +use Nelmio\ApiDocBundle\Formatter\SwaggerFormatter; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; - /** - * Symfony2 command to dump Swagger-compliant JSON files. + * Console command to dump Swagger-compliant API definitions. * * @author Bez Hermoso */ @@ -31,17 +32,21 @@ class SwaggerDumpCommand extends ContainerAwareCommand */ protected $filesystem; - protected $destination; + /** + * @var SwaggerFormatter + */ + protected $formatter; protected function configure() { $this->filesystem = new Filesystem(); $this - ->setDescription('Dump Swagger-compliant JSON files.') - ->addOption('resource', '', InputOption::VALUE_OPTIONAL, 'A specific resource API declaration to dump.') - ->addOption('list-only', '', InputOption::VALUE_NONE, 'Dump resource list only.') - ->addArgument('destination', InputOption::VALUE_OPTIONAL, 'Directory to dump JSON files in.', null) + ->setDescription('Dumps Swagger-compliant API definitions.') + ->addOption('resource', 'r', InputOption::VALUE_OPTIONAL, 'A specific resource API declaration to dump.') + ->addOption('list-only', 'l', InputOption::VALUE_NONE, 'Dump resource list only.') + ->addOption('pretty', 'p', InputOption::VALUE_NONE, 'Dump as prettified JSON.') + ->addArgument('destination', InputArgument::OPTIONAL, 'Directory to dump JSON files in.', null) ->setName('api:swagger:dump'); } @@ -50,26 +55,7 @@ class SwaggerDumpCommand extends ContainerAwareCommand $container = $this->getContainer(); $extractor = $container->get('nelmio_api_doc.extractor.api_doc_extractor'); - - $destination = $input->getArgument('destination'); - - if (count($destination) > 0) { - - $destination = $destination[0]; - - $realpath = realpath($destination); - - if ($realpath == false) { - $rootDir = $container->getParameter('kernel.root_dir'); - $rootDir = realpath($rootDir . '/..'); - $destination = $rootDir . '/' . $destination; - } else { - $destination = $realpath; - } - $this->destination = $destination; - } else { - $this->destination = null; - } + $this->formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); if ($input->getOption('list-only') && $input->getOption('resource')) { throw new \RuntimeException('Cannot selectively dump a resource with the --list-only flag.'); @@ -92,9 +78,12 @@ class SwaggerDumpCommand extends ContainerAwareCommand return; } + /* + * If --list-only and --resource is not specified, dump everything. + */ $data = $this->getResourceList($apiDocs); - if ($this->destination == null) { + if (!$input->getArguments('destination')) { $output->writeln(''); $output->writeln('Resource list: '); } @@ -104,7 +93,7 @@ class SwaggerDumpCommand extends ContainerAwareCommand foreach ($data['apis'] as $api) { $resource = substr($api['path'], 1); - if ($this->destination == null) { + if (!$input->getArgument('destination')) { $output->writeln(''); $output->writeln(sprintf('API declaration for "%s" resource: ', $resource)); } @@ -115,61 +104,60 @@ class SwaggerDumpCommand extends ContainerAwareCommand protected function dump(array $data, $resource, InputInterface $input, OutputInterface $output, $treatAsFile = true) { + $destination = $input->getArgument('destination'); - $content = json_encode($data, JSON_PRETTY_PRINT); + $content = json_encode($data, $input->getOption('pretty') ? JSON_PRETTY_PRINT : 0); - if ($this->destination == null) { + if (!$destination) { $output->writeln($content); return; } - if ($resource == false) { - if ($treatAsFile === false) { - $path = sprintf('%s/api-docs.json', $this->destination); - } else { - $path = $this->destination; + if ($treatAsFile === false) { + if (!$this->filesystem->exists($destination)) { + $this->filesystem->mkdir($destination); } - $string = sprintf('Dumping resource list to %s: ', $path); - $this->writeToFile($data, $path, $output, $string); + } + + if (!$resource) { + + if (!$treatAsFile) { + $destination = sprintf('%s/api-docs.json', rtrim($destination, '\\/')); + } + $message = sprintf('Dumping resource list to %s: ', $destination); + $this->writeToFile($content, $destination, $output, $message); + return; } if ($treatAsFile === false) { - $path = sprintf('%s/%s.json', $this->destination, $resource); - } else { - $path = $this->destination; + $destination = sprintf('%s/%s.json', rtrim($destination, '\\/'), $resource); } - $string = sprintf('Dump API declaration to %s: ', $path); - $this->writeToFile($content, $path, $output, $string); + + $message = sprintf('Dump API declaration to %s: ', $destination); + $this->writeToFile($content, $destination, $output, $message); } - protected function writeToFile($content, $file, OutputInterface $output, $string = null) + protected function writeToFile($content, $file, OutputInterface $output, $message) { - $message = array($string); try { $this->filesystem->dumpFile($file, $content); - $message[] = 'OK'; - $output->writeln(implode(' ', array_filter($message))); + $message .= ' OK'; } catch (IOException $e) { - $message[] = 'NOT OK'; - $output->writeln(implode(' ', array_filter($message))); + $message .= sprintf(' NOT OK - %s', $e->getMessage()); } + + $output->writeln($message); } protected function getResourceList(array $data) { - $container = $this->getContainer(); - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); - $list = $formatter->format($data); - return $list; + return $this->formatter->format($data); } protected function getApiDeclaration(array $data, $resource) { - $container = $this->getContainer(); - $formatter = $container->get('nelmio_api_doc.formatter.swagger_formatter'); - $list = $formatter->format($data, '/' . $resource); - return $list; + return $this->formatter->format($data, '/' . $resource); } -} \ No newline at end of file +} diff --git a/Resources/doc/swagger-support.md b/Resources/doc/swagger-support.md index b2b50fe..b543519 100644 --- a/Resources/doc/swagger-support.md +++ b/Resources/doc/swagger-support.md @@ -80,7 +80,7 @@ Et voila!, simply specify http://yourdomain.com/api-docs in your Swagger client The routes registered with the method above will read your `@ApiDoc` annotation during every request. Naturally, this will be slow because the bundle will parse your annotations every single time. For improved performance, you might be better off dumping the JSON output to the file-system and let your web-server serve them directly. If you want that, execute this command: ``` -php app/console api:swagger:dump --all app/Resources/swagger-docs +php app/console api:swagger:dump app/Resources/swagger-docs ``` The above command will dump JSON files under the `app/Resources/swagger-docs` directory (relative to your project root), and you can now process or server the files however you want. The destination defaults to the project root if not specified. @@ -89,12 +89,12 @@ The above command will dump JSON files under the `app/Resources/swagger-docs` di Dump the `api-docs.json` resource list file only: ``` -php app/console api:swagger:dump --list-only +php app/console api:swagger:dump --list-only api-docs.json ``` Dump a specific resource API declaration only: ``` -php app/console api:swagger:dump --resource=users +php app/console api:swagger:dump --resource=users users.json ``` The above command will dump the `/users` API declaration in an `users.json` file.