Skip to content

Commit

Permalink
feat(openapi): add error resources schemes
Browse files Browse the repository at this point in the history
Allow linking ErrorResources to ApiResources to automatically generate
openapi documentation for errors
  • Loading branch information
JacquesDurand committed Apr 23, 2024
1 parent 6d15e22 commit 9e4dbf3
Show file tree
Hide file tree
Showing 12 changed files with 240 additions and 9 deletions.
8 changes: 5 additions & 3 deletions src/Metadata/Delete.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct(
?array $exceptionToStatus = null,
?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -127,6 +128,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand All @@ -143,6 +145,7 @@ class: $class,
description: $description,
normalizationContext: $normalizationContext,
denormalizationContext: $denormalizationContext,
collectDenormalizationErrors: $collectDenormalizationErrors,
security: $security,
securityMessage: $securityMessage,
securityPostDenormalize: $securityPostDenormalize,
Expand All @@ -169,10 +172,9 @@ class: $class,
name: $name,
provider: $provider,
processor: $processor,
extraProperties: $extraProperties,
collectDenormalizationErrors: $collectDenormalizationErrors,
parameters: $parameters,
stateOptions: $stateOptions,
parameters: $parameters,
extraProperties: $extraProperties,
);
}
}
2 changes: 2 additions & 0 deletions src/Metadata/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct(
?array $exceptionToStatus = null,
?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -125,6 +126,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand Down
2 changes: 2 additions & 0 deletions src/Metadata/Get.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct(
?array $exceptionToStatus = null,
?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -126,6 +127,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand Down
4 changes: 3 additions & 1 deletion src/Metadata/GetCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct(
?array $exceptionToStatus = null,
?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -127,6 +128,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand Down Expand Up @@ -170,9 +172,9 @@ class: $class,
name: $name,
provider: $provider,
processor: $processor,
stateOptions: $stateOptions,
parameters: $parameters,
extraProperties: $extraProperties,
stateOptions: $stateOptions,
);
}

Expand Down
37 changes: 32 additions & 5 deletions src/Metadata/HttpOperation.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace ApiPlatform\Metadata;

use ApiPlatform\Metadata\Exception\InvalidArgumentException;
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
use ApiPlatform\OpenApi\Attributes\Webhook;
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;
use ApiPlatform\State\OptionsInterface;
Expand Down Expand Up @@ -73,11 +75,12 @@ class HttpOperation extends Operation
* class?: string|null,
* name?: string,
* }|string|false|null $output {@see https://api-platform.com/docs/core/dto/#specifying-an-input-or-an-output-data-representation}
* @param string|array|bool|null $mercure {@see https://api-platform.com/docs/core/mercure}
* @param string|bool|null $messenger {@see https://api-platform.com/docs/core/messenger/#dispatching-a-resource-through-the-message-bus}
* @param string|callable|null $provider {@see https://api-platform.com/docs/core/state-providers/#state-providers}
* @param string|callable|null $processor {@see https://api-platform.com/docs/core/state-processors/#state-processors}
* @param WebLink[]|null $links
* @param string|array|bool|null $mercure {@see https://api-platform.com/docs/core/mercure}
* @param string|bool|null $messenger {@see https://api-platform.com/docs/core/messenger/#dispatching-a-resource-through-the-message-bus}
* @param string|callable|null $provider {@see https://api-platform.com/docs/core/state-providers/#state-providers}
* @param string|callable|null $processor {@see https://api-platform.com/docs/core/state-processors/#state-processors}
* @param WebLink[]|null $links
* @param array<class-string<ProblemExceptionInterface>>|null $errors
*/
public function __construct(
protected string $method = 'GET',
Expand Down Expand Up @@ -155,6 +158,7 @@ public function __construct(
protected ?array $exceptionToStatus = null,
protected ?bool $queryParameterValidationEnabled = null,
protected ?array $links = null,
protected ?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -203,6 +207,13 @@ public function __construct(
array|Parameters|null $parameters = null,
array $extraProperties = [],
) {
if (null !== $this->errors) {
foreach ($this->errors as $error) {
if (!(new $error()) instanceof ProblemExceptionInterface) {
throw new InvalidArgumentException(sprintf('The error class "%s" does not implement "%s". Did you forget a use statement?', $error, ProblemExceptionInterface::class));

Check warning on line 213 in src/Metadata/HttpOperation.php

View check run for this annotation

Codecov / codecov/patch

src/Metadata/HttpOperation.php#L211-L213

Added lines #L211 - L213 were not covered by tests
}
}
}
parent::__construct(
shortName: $shortName,
class: $class,
Expand Down Expand Up @@ -635,4 +646,20 @@ public function withLinks(array $links): self

return $self;
}

public function getErrors(): ?array
{
return $this->errors;
}

/**
* @param class-string<ProblemExceptionInterface>[] $errors
*/
public function withErrors(array $errors): self

Check warning on line 658 in src/Metadata/HttpOperation.php

View check run for this annotation

Codecov / codecov/patch

src/Metadata/HttpOperation.php#L658

Added line #L658 was not covered by tests
{
$self = clone $this;
$self->errors = $errors;

Check warning on line 661 in src/Metadata/HttpOperation.php

View check run for this annotation

Codecov / codecov/patch

src/Metadata/HttpOperation.php#L660-L661

Added lines #L660 - L661 were not covered by tests

return $self;

Check warning on line 663 in src/Metadata/HttpOperation.php

View check run for this annotation

Codecov / codecov/patch

src/Metadata/HttpOperation.php#L663

Added line #L663 was not covered by tests
}
}
2 changes: 2 additions & 0 deletions src/Metadata/NotExposed.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public function __construct(

?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -139,6 +140,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand Down
2 changes: 2 additions & 0 deletions src/Metadata/Patch.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct(
?array $exceptionToStatus = null,
?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -127,6 +128,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand Down
2 changes: 2 additions & 0 deletions src/Metadata/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct(
?array $exceptionToStatus = null,
?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -128,6 +129,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand Down
2 changes: 2 additions & 0 deletions src/Metadata/Put.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function __construct(
?array $exceptionToStatus = null,
?bool $queryParameterValidationEnabled = null,
?array $links = null,
?array $errors = null,

?string $shortName = null,
?string $class = null,
Expand Down Expand Up @@ -128,6 +129,7 @@ public function __construct(
exceptionToStatus: $exceptionToStatus,
queryParameterValidationEnabled: $queryParameterValidationEnabled,
links: $links,
errors: $errors,
shortName: $shortName,
class: $class,
paginationEnabled: $paginationEnabled,
Expand Down
16 changes: 16 additions & 0 deletions src/OpenApi/Factory/OpenApiFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use ApiPlatform\JsonSchema\TypeFactoryInterface;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\CollectionOperationInterface;
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
use ApiPlatform\Metadata\HeaderParameterInterface;
use ApiPlatform\Metadata\HttpOperation;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
Expand Down Expand Up @@ -328,6 +329,21 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection

$existingResponses = $openapiOperation?->getResponses() ?: [];
$overrideResponses = $operation->getExtraProperties()[self::OVERRIDE_OPENAPI_RESPONSES] ?? $this->openApiOptions->getOverrideResponses();
if ($operation instanceof HttpOperation && null !== $operation->getErrors()) {
foreach ($operation->getErrors() as $error) {

Check warning on line 333 in src/OpenApi/Factory/OpenApiFactory.php

View check run for this annotation

Codecov / codecov/patch

src/OpenApi/Factory/OpenApiFactory.php#L333

Added line #L333 was not covered by tests
/** @var ProblemExceptionInterface $exception */
$exception = new $error();

Check warning on line 335 in src/OpenApi/Factory/OpenApiFactory.php

View check run for this annotation

Codecov / codecov/patch

src/OpenApi/Factory/OpenApiFactory.php#L335

Added line #L335 was not covered by tests

$operationErrorSchemas = [];
foreach ($responseMimeTypes as $operationFormat) {
$operationErrorSchema = $this->jsonSchemaFactory->buildSchema($error, $operationFormat, Schema::TYPE_OUTPUT, null, $schema, null, $forceSchemaCollection);
$operationErrorSchemas[$operationFormat] = $operationErrorSchema;
$this->appendSchemaDefinitions($schemas, $operationErrorSchema->getDefinitions());

Check warning on line 341 in src/OpenApi/Factory/OpenApiFactory.php

View check run for this annotation

Codecov / codecov/patch

src/OpenApi/Factory/OpenApiFactory.php#L337-L341

Added lines #L337 - L341 were not covered by tests
}

$openapiOperation = $this->buildOpenApiResponse($existingResponses, $exception->getStatus(), $exception->getType(), $openapiOperation, $operation, $responseMimeTypes, $operationErrorSchemas, $resourceMetadataCollection);

Check warning on line 344 in src/OpenApi/Factory/OpenApiFactory.php

View check run for this annotation

Codecov / codecov/patch

src/OpenApi/Factory/OpenApiFactory.php#L344

Added line #L344 was not covered by tests
}
}
if ($overrideResponses || !$existingResponses) {
// Create responses
switch ($method) {
Expand Down
Loading

0 comments on commit 9e4dbf3

Please sign in to comment.