mirror of
https://github.com/retailcrm/NelmioApiDocBundle.git
synced 2025-02-02 15:51:48 +03:00
Add a migration guide
This commit is contained in:
parent
f7c4aae3f9
commit
670bdfa1d0
@ -10,6 +10,10 @@ Version](https://poser.pugx.org/nelmio/api-doc-bundle/v/stable)](https://packagi
|
||||
The **NelmioApiDocBundle** bundle allows you to generate a decent documentation
|
||||
for your APIs.
|
||||
|
||||
## Migrate from 2.x to 3.0
|
||||
|
||||
[To migrate from 2.x to 3.0, just follow our guide.](https://github.com/nelmio/NelmioApiDocBundle/blob/dev/UPGRADE-3.0.md)
|
||||
|
||||
## Installation
|
||||
|
||||
First, open a command console, enter your project directory and execute the following command to download the latest stable version of this bundle:
|
||||
@ -38,6 +42,7 @@ class AppKernel extends Kernel
|
||||
To access your documentation in your browser, register the following route:
|
||||
|
||||
```yml
|
||||
# app/config/routing.yml
|
||||
NelmioApiDocBundle:
|
||||
resource: "@NelmioApiDocBundle/Resources/config/routing/swaggerui.xml"
|
||||
prefix: /api/doc
|
||||
|
288
UPGRADE-3.0.md
Normal file
288
UPGRADE-3.0.md
Normal file
@ -0,0 +1,288 @@
|
||||
Upgrading From 2.x To 3.0
|
||||
=========================
|
||||
|
||||
In 3.0 we did major changes. The biggest is the removal of the `@ApiDoc`
|
||||
annotation. To help you migrate to 3.0, we created this guide.
|
||||
|
||||
Thanks to a command created by @dbu, it should not take too long.
|
||||
|
||||
Step 1: Migrate to Swagger-PHP commands
|
||||
---------------------------------------
|
||||
|
||||
First, copy this command in ``src/AppBundle/Command/SwaggerDocblockConvertCommand.php``:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
// src/AppBundle/Command/SwaggerDocblockConvertCommand.php
|
||||
namespace AppBundle\Command;
|
||||
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Converts ApiDoc annotations to Swagger-PHP annotations.
|
||||
*
|
||||
* @author David Buchmann <david@liip.ch>
|
||||
* @author Guilhem Niot <guilhem.niot@gmail.com>
|
||||
*/
|
||||
class SwaggerDocblockConvertCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('')
|
||||
->setName('api:doc:convert')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$extractor = $this->getContainer()->get('nelmio_api_doc.extractor.api_doc_extractor');
|
||||
$apiDocs = $extractor->extractAnnotations($extractor->getRoutes());
|
||||
|
||||
foreach ($apiDocs as $annotation) {
|
||||
/** @var ApiDoc $apiDoc */
|
||||
$apiDoc = $annotation['annotation'];
|
||||
|
||||
$refl = $extractor->getReflectionMethod($apiDoc->getRoute()->getDefault('_controller'));
|
||||
|
||||
$this->rewriteClass($refl->getFileName(), $refl, $apiDoc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite class with correct apidoc.
|
||||
*/
|
||||
private function rewriteClass(string $path, \ReflectionMethod $method, ApiDoc $apiDoc)
|
||||
{
|
||||
echo "Processing $path::{$method->name}\n";
|
||||
$code = file_get_contents($path);
|
||||
$old = $this->locateNelmioAnnotation($code, $method->name);
|
||||
|
||||
$code = substr_replace($code, $this->renderSwaggerAnnotation($apiDoc, $method), $old['start'], $old['length']);
|
||||
$code = str_replace('use Nelmio\ApiDocBundle\Annotation\ApiDoc;', "use Nelmio\ApiDocBundle\Annotation\Model;\nuse Swagger\Annotations as SWG;", $code);
|
||||
|
||||
file_put_contents($path, $code);
|
||||
}
|
||||
|
||||
private function renderSwaggerAnnotation(ApiDoc $apiDoc, \ReflectionMethod $method): string
|
||||
{
|
||||
$info = $apiDoc->toArray();
|
||||
if ($apiDoc->getResource()) {
|
||||
throw new \RuntimeException('implement me');
|
||||
}
|
||||
$path = str_replace('.{_format}', '', $apiDoc->getRoute()->getPath());
|
||||
|
||||
$annotation = '@SWG\\'.ucfirst(strtolower($apiDoc->getMethod())).'(
|
||||
* tags={"'.$apiDoc->getSection().'"},
|
||||
* summary="'.$this->escapeQuotes($apiDoc->getDescription()).'"';
|
||||
|
||||
foreach ($apiDoc->getFilters() as $name => $parameter) {
|
||||
$description = array_key_exists('description', $parameter)
|
||||
? $this->escapeQuotes($parameter['description'])
|
||||
: 'todo';
|
||||
|
||||
$annotation .= ',
|
||||
* @SWG\Parameter(
|
||||
* name="'.$name.'",
|
||||
* in="query",
|
||||
* description="'.$description.'",
|
||||
* required='.(array_key_exists($name, $apiDoc->getRequirements()) ? 'true' : 'false').',
|
||||
* type="'.$this->determineDataType($parameter).'"
|
||||
* )';
|
||||
}
|
||||
|
||||
// Put parameters for POST requests into formData, as Swagger cannot handle more than one body parameter
|
||||
$in = 'POST' === $apiDoc->getMethod()
|
||||
? 'formData'
|
||||
: 'body';
|
||||
|
||||
foreach ($apiDoc->getParameters() as $name => $parameter) {
|
||||
$description = array_key_exists('description', $parameter)
|
||||
? $this->escapeQuotes($parameter['description'])
|
||||
: 'todo';
|
||||
|
||||
$annotation .= ',
|
||||
* @SWG\Parameter(
|
||||
* name="'.$name.'",
|
||||
* in="'.$in.'",
|
||||
* description="'.$description.'",
|
||||
* required='.(array_key_exists($name, $apiDoc->getRequirements()) ? 'true' : 'false').',
|
||||
* type="'.$this->determineDataType($parameter).'"';
|
||||
|
||||
if ('POST' !== $apiDoc->getMethod()) {
|
||||
$annotation .= ',
|
||||
* schema=""';
|
||||
}
|
||||
|
||||
$annotation .= '
|
||||
* )';
|
||||
}
|
||||
|
||||
if (array_key_exists('statusCodes', $info)) {
|
||||
$responses = $info['statusCodes'];
|
||||
foreach ($responses as $code => $description) {
|
||||
$responses[$code] = reset($description);
|
||||
}
|
||||
} else {
|
||||
$responses = [200 => 'Returned when successful'];
|
||||
}
|
||||
|
||||
$responseMap = $apiDoc->getResponseMap();
|
||||
foreach ($responses as $code => $description) {
|
||||
$annotation .= ",
|
||||
* @SWG\\Response(
|
||||
* response=\"$code\",
|
||||
* description=\"{$this->escapeQuotes($description)}\"";
|
||||
if (200 === $code && isset($responseMap[$code]['class'])) {
|
||||
$model = $responseMap[$code]['class'];
|
||||
$annotation .= ",
|
||||
* @Model(type=\"$model\")";
|
||||
}
|
||||
$annotation .= '
|
||||
* )';
|
||||
}
|
||||
|
||||
$annotation .= '
|
||||
* )
|
||||
*';
|
||||
|
||||
return $annotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array with `start` position and `length`
|
||||
*/
|
||||
private function locateNelmioAnnotation(string $code, string $methodName): array
|
||||
{
|
||||
$position = strpos($code, "tion $methodName(");
|
||||
if (false === $position) {
|
||||
throw new \RuntimeException("Method $methodName not found in controller.");
|
||||
}
|
||||
|
||||
$docstart = strrpos(substr($code, 0, $position), '@ApiDoc');
|
||||
if (false === $docstart) {
|
||||
throw new \RuntimeException("Method $methodName has no @ApiDoc annotation around\n".substr($code, $position - 200, 150));
|
||||
}
|
||||
$docend = strpos($code, '* )', $docstart) + 3;
|
||||
|
||||
return [
|
||||
'start' => $docstart,
|
||||
'length' => $docend - $docstart,
|
||||
];
|
||||
}
|
||||
|
||||
private function escapeQuotes(string $str): string
|
||||
{
|
||||
$lines = [];
|
||||
foreach (explode("\n", $str) as $line) {
|
||||
$lines[] = trim($line, ' *');
|
||||
}
|
||||
|
||||
return str_replace('"', '""', implode(' ', $lines));
|
||||
}
|
||||
|
||||
private function determineDataType(array $parameter): string
|
||||
{
|
||||
$dataType = isset($parameter['dataType']) ? $parameter['dataType'] : 'string';
|
||||
$transform = [
|
||||
'float' => 'number',
|
||||
'datetime' => 'string',
|
||||
];
|
||||
if (array_key_exists($dataType, $transform)) {
|
||||
$dataType = $transform[$dataType];
|
||||
}
|
||||
|
||||
return $dataType;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then open a command console, enter your project directory and run:
|
||||
|
||||
```
|
||||
bin/console api:doc:convert
|
||||
```
|
||||
|
||||
Your annotations should all be converted.
|
||||
|
||||
Note that this tool is here to help you but not all features are supported so
|
||||
make sure the generated annotations still fit your needs.
|
||||
|
||||
Step 2: Update your routing
|
||||
---------------------------
|
||||
|
||||
With NelmioApiDocBundle 2.x, you had to load the
|
||||
``@NelmioApiDocBundle/Resources/config/routing.yml`` file. In 3.0, it was renamed
|
||||
to ``@NelmioApiDocBundle/Resources/config/routing/swaggerui.xml``, so you have
|
||||
to update the ``NelmioApiDocBundle`` route to:
|
||||
|
||||
```yml
|
||||
# app/config/routing.yml
|
||||
NelmioApiDocBundle:
|
||||
resource: "@NelmioApiDocBundle/Resources/config/routing/swaggerui.xml"
|
||||
prefix: /api/doc
|
||||
```
|
||||
|
||||
Step 3: Update your config
|
||||
--------------------------
|
||||
|
||||
* ``nelmio_api_doc.name`` was replaced by ``nelmio_api_doc.documentation.info.title``.
|
||||
|
||||
Before:
|
||||
|
||||
```yml
|
||||
nelmio_api_doc:
|
||||
name: My Awesome App!
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```yml
|
||||
nelmio_api_doc:
|
||||
documentation:
|
||||
info:
|
||||
title: My Awesome App!
|
||||
```
|
||||
|
||||
* ``nelmio_api_doc.swagger.api_version`` was replaced by ``nelmio_api_doc.documentation.info.version``.
|
||||
|
||||
* ``nelmio_api_doc.swagger.info.title`` was replaced by ``nelmio_api_doc.documentation.info.title``.
|
||||
|
||||
* ``nelmio_api_doc.swagger.info.description`` was replaced by ``nelmio_api_doc.documentation.info.description``.
|
||||
|
||||
* Other options were removed.
|
||||
|
||||
Step 4: Update the bundle
|
||||
-------------------------
|
||||
|
||||
Change the constraint of ``nelmio/api-doc-bundle`` in your ``composer.json`` file
|
||||
to ``dev-dev``:
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"nelmio/api-doc-bundle": "dev-dev"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then update your dependencies:
|
||||
|
||||
```
|
||||
composer update
|
||||
```
|
||||
|
||||
Step 5: Review the changes
|
||||
--------------------------
|
||||
|
||||
It's almost finished!
|
||||
|
||||
As most of the changes were automated you should check that they did not break
|
||||
anything. Run your test suite, review, do whatever you think is useful before
|
||||
pushing the changes.
|
||||
|
||||
Then, commit the changes, push them, and enjoy!
|
Loading…
x
Reference in New Issue
Block a user