Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 36 additions & 14 deletions src/OpenApi/Factory/OpenApiFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -279,38 +279,44 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
}
}

$existingResponses = $openapiOperation?->getResponses() ?: [];
// Create responses
switch ($method) {
case HttpOperation::METHOD_GET:
$successStatus = (string) $operation->getStatus() ?: 200;
$responseContent = $this->buildContent($responseMimeTypes, $operationOutputSchemas);
$openapiOperation = $openapiOperation->withResponse($successStatus, new Response(sprintf('%s %s', $resourceShortName, $operation instanceof CollectionOperationInterface ? 'collection' : 'resource'), $responseContent));
$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s %s', $resourceShortName, $operation instanceof CollectionOperationInterface ? 'collection' : 'resource'), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas);
break;
case HttpOperation::METHOD_POST:
$responseLinks = $this->getLinks($resourceMetadataCollection, $operation);
$responseContent = $this->buildContent($responseMimeTypes, $operationOutputSchemas);
$successStatus = (string) $operation->getStatus() ?: 201;
$openapiOperation = $openapiOperation->withResponse($successStatus, new Response(sprintf('%s resource created', $resourceShortName), $responseContent, null, $responseLinks));
$openapiOperation = $openapiOperation->withResponse(400, new Response('Invalid input'));
$openapiOperation = $openapiOperation->withResponse(422, new Response('Unprocessable entity'));

$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource created', $resourceShortName), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas, $resourceMetadataCollection);

$openapiOperation = $this->buildOpenApiResponse($existingResponses, '400', 'Invalid input', $openapiOperation);

$openapiOperation = $this->buildOpenApiResponse($existingResponses, '422', 'Unprocessable entity', $openapiOperation);
break;
case HttpOperation::METHOD_PATCH:
case HttpOperation::METHOD_PUT:
$responseLinks = $this->getLinks($resourceMetadataCollection, $operation);
$successStatus = (string) $operation->getStatus() ?: 200;
$responseContent = $this->buildContent($responseMimeTypes, $operationOutputSchemas);
$openapiOperation = $openapiOperation->withResponse($successStatus, new Response(sprintf('%s resource updated', $resourceShortName), $responseContent, null, $responseLinks));
$openapiOperation = $openapiOperation->withResponse(400, new Response('Invalid input'));
$openapiOperation = $openapiOperation->withResponse(422, new Response('Unprocessable entity'));
$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource updated', $resourceShortName), $openapiOperation, $operation, $responseMimeTypes, $operationOutputSchemas, $resourceMetadataCollection);
$openapiOperation = $this->buildOpenApiResponse($existingResponses, '400', 'Invalid input', $openapiOperation);
if (!isset($existingResponses[400])) {
$openapiOperation = $openapiOperation->withResponse(400, new Response('Invalid input'));
}
$openapiOperation = $this->buildOpenApiResponse($existingResponses, '422', 'Unprocessable entity', $openapiOperation);
break;
case HttpOperation::METHOD_DELETE:
$successStatus = (string) $operation->getStatus() ?: 204;
$openapiOperation = $openapiOperation->withResponse($successStatus, new Response(sprintf('%s resource deleted', $resourceShortName)));

$openapiOperation = $this->buildOpenApiResponse($existingResponses, $successStatus, sprintf('%s resource deleted', $resourceShortName), $openapiOperation);

break;
}

if (!$operation instanceof CollectionOperationInterface && HttpOperation::METHOD_POST !== $operation->getMethod()) {
$openapiOperation = $openapiOperation->withResponse(404, new Response('Resource not found'));
if (!isset($existingResponses[404])) {
$openapiOperation = $openapiOperation->withResponse(404, new Response('Resource not found'));
}
}

if (!$openapiOperation->getResponses()) {
Expand Down Expand Up @@ -377,6 +383,22 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
}
}

private function buildOpenApiResponse(array $existingResponses, int|string $status, string $description, Model\Operation $openapiOperation = null, HttpOperation $operation = null, array $responseMimeTypes = null, array $operationOutputSchemas = null, ResourceMetadataCollection $resourceMetadataCollection = null): Model\Operation
{
if (isset($existingResponses[$status])) {
return $openapiOperation;
}
$responseLinks = $responseContent = null;
if ($responseMimeTypes && $operationOutputSchemas) {
$responseContent = $this->buildContent($responseMimeTypes, $operationOutputSchemas);
}
if ($resourceMetadataCollection && $operation) {
$responseLinks = $this->getLinks($resourceMetadataCollection, $operation);
}

return $openapiOperation->withResponse($status, new Response($description, $responseContent, null, $responseLinks));
}

/**
* @return \ArrayObject<Model\MediaType>
*/
Expand Down
151 changes: 151 additions & 0 deletions tests/OpenApi/Factory/OpenApiFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,55 @@ public function testInvoke(): void
]),
),
)),
'putDummyItemWithResponse' => (new Put())->withUriTemplate('/dummyitems/{id}')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
responses: [
'200' => new OpenApiResponse(
description: 'Success',
content: new \ArrayObject([
'application/json' => [
'schema' => ['$ref' => '#/components/schemas/Dummy'],
],
]),
headers: new \ArrayObject([
'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
]),
links: new \ArrayObject([
'link' => ['$ref' => '#/components/schemas/Dummy'],
]),
),
'400' => new OpenApiResponse(
description: 'Error',
),
],
)),
'getDummyItemImageCollection' => (new GetCollection())->withUriTemplate('/dummyitems/{id}/images')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
responses: [
'200' => new OpenApiResponse(
description: 'Success',
),
],
)),
'postDummyItemWithResponse' => (new Post())->withUriTemplate('/dummyitems')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
responses: [
'201' => new OpenApiResponse(
description: 'Created',
content: new \ArrayObject([
'application/json' => [
'schema' => ['$ref' => '#/components/schemas/Dummy'],
],
]),
headers: new \ArrayObject([
'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
]),
links: new \ArrayObject([
'link' => ['$ref' => '#/components/schemas/Dummy'],
]),
),
'400' => new OpenApiResponse(
description: 'Error',
),
],
)),
])
);

Expand Down Expand Up @@ -694,5 +743,107 @@ public function testInvoke(): void
),
deprecated: false,
), $requestBodyPath->getPost());

$dummyItemPath = $paths->getPath('/dummyitems/{id}');
$this->assertEquals(new Operation(
'putDummyItemWithResponse',
['Dummy'],
[
'200' => new Response(
'Success',
new \ArrayObject([
'application/json' => [
'schema' => ['$ref' => '#/components/schemas/Dummy'],
],
]),
new \ArrayObject([
'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
]),
new \ArrayObject([
'link' => ['$ref' => '#/components/schemas/Dummy'],
])
),
'400' => new Response('Error'),
'422' => new Response('Unprocessable entity'),
'404' => new Response('Resource not found'),
],
'Replaces the Dummy resource.',
'Replaces the Dummy resource.',
null,
[],
new RequestBody(
'The updated Dummy resource',
new \ArrayObject([
'application/ld+json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy'])),
]),
true
),
deprecated: false
), $dummyItemPath->getPut());

$dummyItemPath = $paths->getPath('/dummyitems');
$this->assertEquals(new Operation(
'postDummyItemWithResponse',
['Dummy'],
[
'201' => new Response(
'Created',
new \ArrayObject([
'application/json' => [
'schema' => ['$ref' => '#/components/schemas/Dummy'],
],
]),
new \ArrayObject([
'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
]),
new \ArrayObject([
'link' => ['$ref' => '#/components/schemas/Dummy'],
])
),
'400' => new Response('Error'),
'422' => new Response('Unprocessable entity'),
],
'Creates a Dummy resource.',
'Creates a Dummy resource.',
null,
[],
new RequestBody(
'The new Dummy resource',
new \ArrayObject([
'application/ld+json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy'])),
]),
true
),
deprecated: false
), $dummyItemPath->getPost());

$dummyItemPath = $paths->getPath('/dummyitems/{id}/images');

$this->assertEquals(new Operation(
'getDummyItemImageCollection',
['Dummy'],
[
'200' => new Response(
'Success'
),
],
'Retrieves the collection of Dummy resources.',
'Retrieves the collection of Dummy resources.',
null,
[
new Parameter('page', 'query', 'The collection page number', false, false, true, [
'type' => 'integer',
'default' => 1,
]),
new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, true, [
'type' => 'integer',
'default' => 30,
'minimum' => 0,
]),
new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, true, [
'type' => 'boolean',
]),
]
), $dummyItemPath->getGet());
}
}