Skip to content

Commit 1fe82c6

Browse files
authored
Merge pull request #9 from Tobion/openapi-v3
support OpenAPI v3 / zwagger-php 3.x
2 parents 4e8e5c3 + 6fa8297 commit 1fe82c6

15 files changed

Lines changed: 126 additions & 97 deletions

File tree

README.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ Loads routes in Symfony based on [OpenAPI/Swagger annotations](https://github.co
88

99
$ composer require tobion/openapi-symfony-routing
1010

11+
Version >= 1.2 requires zircote/swagger-php 3.x which is compatible with the OpenAPI Specification version 3.
12+
Version < 1.2 requires zircote/swagger-php 2.x which works with the OpenAPI Specification version 2 (fka Swagger).
13+
So tobion/openapi-symfony-routing can be used with both OpenAPI v2 and v3 and composer will select the compatible one for your dependencies.
14+
Route loading stays the same between version. You just need to update the annotations when migrating from OpenAPI v2 to v3.
15+
1116
## Basic Usage
1217

1318
This library allows to (re-)use your OpenAPI documentation to configure the routing of your Symfony-based API.
@@ -16,19 +21,19 @@ This way you do not have to duplicate any routing information in Symfony. Consid
1621
[zircote/swagger-php](https://github.com/zircote/swagger-php) like the following example:
1722

1823
```php
19-
use Swagger\Annotations as SWG;
24+
use OpenApi\Annotations as OA;
2025

2126
/**
22-
* @SWG\Swagger(
23-
* @SWG\Info(title="My API", version="1.0")
27+
* @OA\OpenApi(
28+
* @OA\Info(title="My API", version="1.0")
2429
* )
2530
*/
2631
class MyController
2732
{
2833
/**
29-
* @SWG\Get(
34+
* @OA\Get(
3035
* path="/foobar",
31-
* @SWG\Response(response="200", description="Success")
36+
* @OA\Response(response="200", description="Success")
3237
* )
3338
*/
3439
public function __invoke()
@@ -77,15 +82,15 @@ By default routes are auto-named based on the controller class and method. If yo
7782
an explicit name, you can do so using the OpenAPI `operationId` property:
7883

7984
```php
80-
use Swagger\Annotations as SWG;
85+
use OpenApi\Annotations as OA;
8186
8287
class MyController
8388
{
8489
/**
85-
* @SWG\Get(
90+
* @OA\Get(
8691
* path="/foobar",
8792
* operationId="my-name",
88-
* @SWG\Response(response="200", description="Success")
93+
* @OA\Response(response="200", description="Success")
8994
* )
9095
*/
9196
public function __invoke()
@@ -102,18 +107,18 @@ The routing loader allows to add a `.{_format}` placeholder automatically to the
102107
and can be enabled using a `format-suffix` OpenAPI vendor extension:
103108

104109
```php
105-
use Swagger\Annotations as SWG;
110+
use OpenApi\Annotations as OA;
106111
107112
class MyController
108113
{
109114
/**
110-
* @SWG\Get(
115+
* @OA\Get(
111116
* path="/foobar",
112117
* x={"format-suffix": {
113118
* "enabled": true,
114119
* "pattern": "json|xml"
115120
* }},
116-
* @SWG\Response(response="200", description="Success")
121+
* @OA\Response(response="200", description="Success")
117122
* )
118123
*/
119124
public function __invoke()
@@ -123,7 +128,7 @@ class MyController
123128
```
124129

125130
The above example will create a route `/foobar.{_format}` where the format is optional and can be json or xml.
126-
You can also enable the format-suffix globally by configuring it on the root Swagger annotation and disable it for
131+
You can also enable the format-suffix globally by configuring it on the root OpenApi annotation and disable it for
127132
certain routes again, see [test fixtures](./tests/Fixtures/FormatSuffix/Controller.php).
128133

129134
### Order routes with priority
@@ -133,15 +138,15 @@ This can be used to make sure templated routes do not match before concrete rout
133138
The priority can also be set on OpenAPI annotations using a `priority` vendor extension:
134139

135140
```php
136-
use Swagger\Annotations as SWG;
141+
use OpenApi\Annotations as OA;
137142
138143
class MyController
139144
{
140145
/**
141-
* @SWG\Get(
146+
* @OA\Get(
142147
* path="/foobar",
143148
* x={"priority": 10},
144-
* @SWG\Response(response="200", description="Success")
149+
* @OA\Response(response="200", description="Success")
145150
* )
146151
*/
147152
public function __invoke()

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"symfony/finder": "^4.4|^5.0",
1717
"symfony/framework-bundle": "^4.4|^5.0",
1818
"symfony/routing": "^4.4|^5.0",
19-
"zircote/swagger-php": "^2.1"
19+
"zircote/swagger-php": "^3.0.3"
2020
},
2121
"require-dev": {
2222
"symfony/phpunit-bridge": "^5.2"

src/FormatSuffixConfig.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Tobion\OpenApiSymfonyRouting;
66

7-
use Swagger\Annotations\AbstractAnnotation;
7+
use OpenApi\Annotations\AbstractAnnotation;
88

99
/**
1010
* @internal

src/OpenApiRouteLoader.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Tobion\OpenApiSymfonyRouting;
66

7-
use Swagger\Annotations\Operation;
7+
use OpenApi\Annotations\Operation;
88
use Symfony\Bundle\FrameworkBundle\Routing\RouteLoaderInterface;
99
use Symfony\Component\Finder\Finder;
1010
use Symfony\Component\Routing\Route;
@@ -44,7 +44,7 @@ public static function fromSrcDirectory(): self
4444

4545
public function __invoke(): RouteCollection
4646
{
47-
$openApi = \Swagger\scan($this->finder);
47+
$openApi = \OpenApi\scan($this->finder);
4848
$routeCollection = new RouteCollection();
4949

5050
$globalFormatSuffixConfig = FormatSuffixConfig::fromAnnotation($openApi);
@@ -66,9 +66,12 @@ public function __invoke(): RouteCollection
6666
return $routeCollection;
6767
}
6868

69-
private function addRouteFromOpenApiOperation(RouteCollection $routeCollection, ?Operation $operation, FormatSuffixConfig $parentFormatSuffixConfig): void
69+
/**
70+
* @param Operation|string $operation
71+
*/
72+
private function addRouteFromOpenApiOperation(RouteCollection $routeCollection, $operation, FormatSuffixConfig $parentFormatSuffixConfig): void
7073
{
71-
if (null === $operation) {
74+
if (\OpenApi\UNDEFINED === $operation || !$operation instanceof Operation) {
7275
return;
7376
}
7477

@@ -95,10 +98,10 @@ private function createRoute(Operation $operation, string $controller, FormatSuf
9598
$route->setRequirement('_format', $formatSuffixConfig->pattern);
9699
}
97100
}
98-
if (null !== $operation->parameters) {
101+
if (\OpenApi\UNDEFINED !== $operation->parameters) {
99102
foreach ($operation->parameters as $parameter) {
100-
if ('path' === $parameter->in && null !== $parameter->pattern) {
101-
$route->setRequirement($parameter->name, $parameter->pattern);
103+
if ('path' === $parameter->in && \OpenApi\UNDEFINED !== $parameter->schema && \OpenApi\UNDEFINED !== $parameter->schema->pattern) {
104+
$route->setRequirement($parameter->name, $parameter->schema->pattern);
102105
}
103106
}
104107
}
@@ -115,7 +118,10 @@ private function getControllerFromOpenApiOperation(Operation $operation): string
115118

116119
private function getRouteName(Operation $operation, string $controller): string
117120
{
118-
return \Swagger\UNDEFINED === $operation->operationId ? $this->getDefaultRouteName($controller) : $operation->operationId;
121+
// swagger-php v3 adds the controller as operationId automatically, see \OpenApi\Processors\OperationId.
122+
// This must be ignored as it is not viable with multiple annotations on the same controller.
123+
124+
return \OpenApi\UNDEFINED === $operation->operationId || $controller === $operation->operationId ? $this->getDefaultRouteName($controller) : $operation->operationId;
119125
}
120126

121127
private function getRoutePriority(Operation $operation): int

tests/Fixtures/Basic/Controller.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44

55
namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\Basic;
66

7-
use Swagger\Annotations as SWG;
7+
use OpenApi\Annotations as OA;
88

99
/**
10-
* @SWG\Swagger(
11-
* @SWG\Info(title="My API", version="1.0")
10+
* @OA\OpenApi(
11+
* @OA\Info(title="My API", version="1.0")
1212
* )
1313
*/
1414
class Controller
1515
{
1616
/**
17-
* @SWG\Get(
17+
* @OA\Get(
1818
* path="/foobar",
19-
* @SWG\Response(response="200", description="Success")
19+
* @OA\Response(response="200", description="Success")
2020
* )
2121
*/
2222
public function __invoke(): void

tests/Fixtures/FormatSuffix/Controller.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\FormatSuffix;
66

7-
use Swagger\Annotations as SWG;
7+
use OpenApi\Annotations as OA;
88

99
/**
10-
* @SWG\Swagger(
11-
* @SWG\Info(title="My API", version="1.0"),
10+
* @OA\OpenApi(
11+
* @OA\Info(title="My API", version="1.0"),
1212
* x={"format-suffix": {
1313
* "enabled": true
1414
* }}
@@ -17,33 +17,33 @@
1717
class Controller
1818
{
1919
/**
20-
* @SWG\Get(
20+
* @OA\Get(
2121
* path="/a",
22-
* @SWG\Response(response="200", description="Success")
22+
* @OA\Response(response="200", description="Success")
2323
* )
2424
*/
2525
public function inheritEnabledFormatSuffix(): void
2626
{
2727
}
2828

2929
/**
30-
* @SWG\Get(
30+
* @OA\Get(
3131
* path="/b",
3232
* x={"format-suffix": {
3333
* "pattern": "json|xml"
3434
* }},
35-
* @SWG\Response(response="200", description="Success")
35+
* @OA\Response(response="200", description="Success")
3636
* )
3737
*/
3838
public function defineFormatPattern(): void
3939
{
4040
}
4141

4242
/**
43-
* @SWG\Get(
43+
* @OA\Get(
4444
* path="/c",
4545
* x={"format-suffix": false},
46-
* @SWG\Response(response="200", description="Success")
46+
* @OA\Response(response="200", description="Success")
4747
* )
4848
*/
4949
public function disableFormatSuffix(): void

tests/Fixtures/OperationId/Controller.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44

55
namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\OperationId;
66

7-
use Swagger\Annotations as SWG;
7+
use OpenApi\Annotations as OA;
88

99
/**
10-
* @SWG\Swagger(
11-
* @SWG\Info(title="My API", version="1.0")
10+
* @OA\OpenApi(
11+
* @OA\Info(title="My API", version="1.0")
1212
* )
1313
*/
1414
class Controller
1515
{
1616
/**
17-
* @SWG\Get(
17+
* @OA\Get(
1818
* path="/foobar",
1919
* operationId="my-name",
20-
* @SWG\Response(response="200", description="Success")
20+
* @OA\Response(response="200", description="Success")
2121
* )
2222
*/
2323
public function __invoke(): void

tests/Fixtures/PathParameterPattern/Controller.php

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,56 @@
44

55
namespace Tobion\OpenApiSymfonyRouting\Tests\Fixtures\PathParameterPattern;
66

7-
use Swagger\Annotations as SWG;
7+
use OpenApi\Annotations as OA;
88

99
/**
10-
* @SWG\Swagger(
11-
* @SWG\Info(title="My API", version="1.0")
10+
* @OA\OpenApi(
11+
* @OA\Info(title="My API", version="1.0")
1212
* )
1313
*/
1414
class Controller
1515
{
1616
/**
17-
* @SWG\Get(
17+
* @OA\Get(
1818
* path="/foo/{id}",
19-
* @SWG\Parameter(
19+
* @OA\Parameter(
2020
* name="id",
2121
* in="path",
22-
* type="string",
23-
* required=true
22+
* required=true,
23+
* @OA\Schema(type="string")
2424
* ),
25-
* @SWG\Response(response="200", description="Success")
25+
* @OA\Response(response="200", description="Success")
2626
* )
2727
*/
2828
public function noPattern(): void
2929
{
3030
}
3131

3232
/**
33-
* @SWG\Get(
33+
* @OA\Get(
34+
* path="/baz/{id}",
35+
* @OA\Parameter(
36+
* name="id",
37+
* in="path",
38+
* required=true
39+
* ),
40+
* @OA\Response(response="200", description="Success")
41+
* )
42+
*/
43+
public function noSchema(): void
44+
{
45+
}
46+
47+
/**
48+
* @OA\Get(
3449
* path="/bar/{id}",
35-
* @SWG\Parameter(
50+
* @OA\Parameter(
3651
* name="id",
3752
* in="path",
38-
* type="string",
3953
* required=true,
40-
* pattern="^[a-zA-Z0-9]+$"
54+
* @OA\Schema(type="string", pattern="^[a-zA-Z0-9]+$")
4155
* ),
42-
* @SWG\Response(response="200", description="Success")
56+
* @OA\Response(response="200", description="Success")
4357
* )
4458
*/
4559
public function withPattern(): void

0 commit comments

Comments
 (0)