Skip to content

Commit

Permalink
Add support for OpenApi 3.1.0 Webhooks (zircote#1511)
Browse files Browse the repository at this point in the history
  • Loading branch information
DerManoMann authored Dec 11, 2023
1 parent 8ea52e3 commit 5087638
Show file tree
Hide file tree
Showing 16 changed files with 443 additions and 89 deletions.
12 changes: 7 additions & 5 deletions Examples/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ Collection of code/annotation examples and their corresponding OpenAPI specs gen
* misc: [source](misc) / [spec](misc/misc.yaml)
* using interfaces: [source](using-interfaces) / [spec](using-interfaces/using-interfaces.yaml)
* using traits: [source](using-traits) / [spec](using-traits/using-traits.yaml)
* using refs: [source](using-refs) / [spec](using-refs/using-refs.yaml)
* using refs: [source](using-refs) / [spec](using-refs/using-refs.yaml)
* nested schemas and class hierachies: [source](nesting) / [spec](nesting/nesting.yaml)
* polymorphism using `@OA\Discriminator`: [source](polymorphism) / [spec](polymorphism/polymorphism.yaml)

* webhooks using `@OA\Webhooks`: [source](webhooks) / [spec](webhooks/webhooks.yaml)
* webhooks81 using `@OAT\Webhooks`: [source](webhooks81) / [spec](webhooks81/webhooks.yaml)


## Custom processors

Expand All @@ -52,10 +54,10 @@ class MyCustomProcessor
{
public function __invoke(Analysis $analysis)
{
// custom processing
// custom processing
}
}
```
```

* **schema-query-parameter processor**

Expand All @@ -66,6 +68,6 @@ class MyCustomProcessor

* **sort-components processor**

A processor that sorts components so they appear in alphabetical order.
A processor that sorts components so they appear in alphabetical order.

[source](processors/sort-components)
34 changes: 34 additions & 0 deletions Examples/webhooks/OpenApiSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php declare(strict_types=1);

namespace OpenApi\Examples\Webhooks;

use OpenApi\Annotations as OA;

/**
* @OA\OpenApi(
* @OA\Info(
* version="1.0.0",
* title="Webhook Example"
* ),
* @OA\Webhook(
* webhook="newPet",
* @OA\Post(
* @OA\RequestBody(
* description="Information about a new pet in the system",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(ref="#/components/schemas/Pet")
* )
* ),
* @OA\Response(
* response=200,
* description="Return a 200 status to indicate that the data was received successfully"
* )
* )
* )
* )
* )
*/
class OpenApiSpec
{
}
32 changes: 32 additions & 0 deletions Examples/webhooks/Pet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);

namespace OpenApi\Examples\Webhooks;

use OpenApi\Annotations as OA;

/**
* @OA\Schema(required={"id", "name"})
*/
final class Pet
{
/**
* @OA\Property(format="int64")
*
* @var int
*/
public $id;

/**
* @OA\Property
*
* @var string
*/
public $name;

/**
* @OA\Property
*
* @var string
*/
public $tag;
}
32 changes: 32 additions & 0 deletions Examples/webhooks/webhooks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
openapi: 3.1.0
info:
title: 'Webhook Example'
version: 1.0.0
components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
type: object
webhooks:
newPet:
post:
operationId: 072580cbd56e3fef2b4c81536d3fd1c6
requestBody:
description: 'Information about a new pet in the system'
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
responses:
'200':
description: 'Return a 200 status to indicate that the data was received successfully'
32 changes: 32 additions & 0 deletions Examples/webhooks81/OpenApiSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);

namespace OpenApi\Examples\Webhooks81;

use OpenApi\Attributes as OAT;

#[OAT\OpenApi(
info: new OAT\Info(version: '1.0.0', title: 'Webhook Example'),
webhooks: [
new OAT\Webhook(
webhook: 'newPet',
post: new OAT\Post(
requestBody: new OAT\RequestBody(
description: 'Information about a new pet in the system',
content: new OAT\MediaType(
mediaType: 'application/json',
schema: new OAT\Schema(ref: Pet::class)
)
),
responses: [
new OAT\Response(
response: 200,
description: 'Return a 200 status to indicate that the data was received successfully'
),
]
)
),
],
)]
class OpenApiSpec
{
}
18 changes: 18 additions & 0 deletions Examples/webhooks81/Pet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php declare(strict_types=1);

namespace OpenApi\Examples\Webhooks81;

use OpenApi\Attributes as OAT;

#[OAT\Schema(required: ['id', 'name'])]
final class Pet
{
#[OAT\Property(format: 'int64')]
public int $id;

#[OAT\Property]
public string $name;

#[OAT\Property]
public string $tag;
}
32 changes: 32 additions & 0 deletions Examples/webhooks81/webhooks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
openapi: 3.1.0
info:
title: 'Webhook Example'
version: 1.0.0
components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
type: object
webhooks:
newPet:
post:
operationId: bbbe318bf00166ae6ba3552197e5f089
requestBody:
description: 'Information about a new pet in the system'
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
responses:
'200':
description: 'Return a 200 status to indicate that the data was received successfully'
1 change: 1 addition & 0 deletions src/Annotations/Attachable.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class Attachable extends AbstractAnnotation
ServerVariable::class,
Tag::class,
Trace::class,
Webhook::class,
Xml::class,
XmlContent::class,
];
Expand Down
40 changes: 39 additions & 1 deletion src/Annotations/OpenApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ class OpenApi extends AbstractAnnotation
*/
public $externalDocs = Generator::UNDEFINED;

/**
* The available webhooks for the API.
*
* @var Webhook[]
*/
public $webhooks = Generator::UNDEFINED;

/**
* @var Analysis
*/
Expand All @@ -106,7 +113,7 @@ class OpenApi extends AbstractAnnotation
/**
* @inheritdoc
*/
public static $_required = ['openapi', 'info', 'paths'];
public static $_required = ['openapi', 'info'];

/**
* @inheritdoc
Expand All @@ -118,6 +125,7 @@ class OpenApi extends AbstractAnnotation
Components::class => 'components',
Tag::class => ['tags'],
ExternalDocumentation::class => 'externalDocs',
Webhook::class => ['webhooks', 'webhook'],
Attachable::class => ['attachables'],
];

Expand All @@ -143,6 +151,21 @@ public function validate(array $stack = null, array $skip = null, string $ref =
return false;
}

/* paths is optional in 3.1.0 */
if ($this->openapi === self::VERSION_3_0_0 && Generator::isDefault($this->paths)) {
$this->_context->logger->warning('Required @OA\PathItem() not found');
}

if ($this->openapi === self::VERSION_3_1_0
&& Generator::isDefault($this->paths)
&& Generator::isDefault($this->webhooks)
&& Generator::isDefault($this->components)
) {
$this->_context->logger->warning("At least one of 'Required @OA\PathItem(), @OA\Components() or @OA\Webhook() not found'");

return false;
}

return parent::validate([], [], '#', new \stdClass());
}

Expand Down Expand Up @@ -230,4 +253,19 @@ private static function resolveRef(string $ref, string $resolved, $container, ar

throw new \Exception('$ref "' . $unresolved . '" not found');
}

/**
* @inheritdoc
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
$data = parent::jsonSerialize();

if (false === $this->_context->isVersion(OpenApi::VERSION_3_1_0)) {
unset($data->webhooks);
}

return $data;
}
}
43 changes: 43 additions & 0 deletions src/Annotations/Webhook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types=1);

/**
* @license Apache 2.0
*/

namespace OpenApi\Annotations;

use OpenApi\Generator;

/**
* Acts like a `PathItem` with the main difference being that it requires `webhook` instead of `path`.
*
* @Annotation
*/
class Webhook extends PathItem
{
/**
* Key for the webhooks map.
*
* @var string
*/
public $webhook = Generator::UNDEFINED;

/**
* @inheritdoc
*/
public static $_required = ['webhook'];

/**
* @inheritdoc
*/
public static $_parents = [
OpenApi::class,
];

/**
* @inheritdoc
*/
public static $_types = [
'webhook' => 'string',
];
}
4 changes: 3 additions & 1 deletion src/Attributes/OpenApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class OpenApi extends \OpenApi\Annotations\OpenApi
* @param Server[]|null $servers
* @param Tag[]|null $tags
* @param PathItem[]|null $paths
* @param Webhook[]|null $webhooks
* @param array<string,mixed>|null $x
* @param Attachable[]|null $attachables
*/
Expand All @@ -27,6 +28,7 @@ public function __construct(
?ExternalDocumentation $externalDocs = null,
?array $paths = null,
?Components $components = null,
?array $webhooks = null,
// annotation
?array $x = null,
?array $attachables = null
Expand All @@ -35,7 +37,7 @@ public function __construct(
'openapi' => $openapi,
'security' => $security ?? Generator::UNDEFINED,
'x' => $x ?? Generator::UNDEFINED,
'value' => $this->combine($info, $servers, $tags, $externalDocs, $paths, $components, $attachables),
'value' => $this->combine($info, $servers, $tags, $externalDocs, $paths, $components, $webhooks, $attachables),
]);
}
}
Loading

0 comments on commit 5087638

Please sign in to comment.