-
-
Notifications
You must be signed in to change notification settings - Fork 849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Swagger Path Identifier to reflect the annotation of ApiProperty(identifier=true) #1367
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ | |
/** | ||
* Creates a machine readable Swagger API documentation. | ||
* | ||
* @author Philippe Guilbault <philippe.guilbault@gmail.com> | ||
* @author Amrouche Hamza <hamza.simperfit@gmail.com> | ||
* @author Teoh Han Hui <teohhanhui@gmail.com> | ||
* @author Kévin Dunglas <dunglas@gmail.com> | ||
|
@@ -303,12 +304,7 @@ private function updateGetOperation(\ArrayObject $pathOperation, array $mimeType | |
} | ||
|
||
$pathOperation['summary'] ?? $pathOperation['summary'] = sprintf('Retrieves a %s resource.', $resourceShortName); | ||
$pathOperation['parameters'] ?? $pathOperation['parameters'] = [[ | ||
'name' => 'id', | ||
'in' => 'path', | ||
'required' => true, | ||
'type' => 'string', | ||
]]; | ||
$pathOperation['parameters'] ?? $pathOperation['parameters'] = $this->getPathParameters($resourceClass); | ||
$pathOperation['responses'] ?? $pathOperation['responses'] = [ | ||
'200' => [ | ||
'description' => sprintf('%s resource response', $resourceShortName), | ||
|
@@ -320,6 +316,56 @@ private function updateGetOperation(\ArrayObject $pathOperation, array $mimeType | |
return $pathOperation; | ||
} | ||
|
||
/** | ||
* Returns an array of swagger path parameters according to the provided class' identifiers | ||
* | ||
* @param string $resourceClass | ||
* @return array | ||
*/ | ||
private function getPathParameters(string $resourceClass) | ||
{ | ||
$parameters = []; | ||
$properties = $this->getClassIdentifiers($resourceClass); | ||
foreach ($properties as $propertyName => $property) { | ||
$parameters[] = [ | ||
'name' => $propertyName, | ||
'in' => 'path', | ||
'required' => true, | ||
'type' => $property->getType()->getBuiltinType(), | ||
]; | ||
} | ||
|
||
if (empty($parameters)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if (!$identifiers = $this->getClassIdentifiers($resourceClass)) {
return [[
'name' => 'id',
'in' => 'path',
'required' => true,
'type' => 'string',
]];
}
$parameters = [];
foreach ($identifiers as $identifier => $property) {
$parameters[] = [ ... ];
}
return $parameters; |
||
$parameters = [[ | ||
'name' => "id", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use simple quotes. |
||
'in' => 'path', | ||
'required' => true, | ||
'type' => "string", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use simple quotes. |
||
]]; | ||
} | ||
|
||
return $parameters; | ||
} | ||
|
||
/** | ||
* Returns all the identifier properties for the given class | ||
* | ||
* @param string $resourceClass | ||
* @return PropertyMetadata[] | ||
*/ | ||
private function getClassIdentifiers(string $resourceClass) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you follow the same strategy as https://github.com/api-platform/core/pull/1358/files#diff-6ad90c31c0386b8ef6b541a28614c002? |
||
{ | ||
$identifiers = []; | ||
foreach ($this->propertyNameCollectionFactory->create($resourceClass, []) as $propertyName) { | ||
$property = $this->propertyMetadataFactory->create($resourceClass, $propertyName); | ||
if ($property->isIdentifier()) { | ||
$identifiers[$propertyName] = $property; | ||
} | ||
} | ||
|
||
return $identifiers; | ||
} | ||
|
||
/** | ||
* @param \ArrayObject $pathOperation | ||
* @param array $mimeTypes | ||
|
@@ -376,13 +422,7 @@ private function updatePutOperation(\ArrayObject $pathOperation, array $mimeType | |
$pathOperation['consumes'] ?? $pathOperation['consumes'] = $mimeTypes; | ||
$pathOperation['produces'] ?? $pathOperation['produces'] = $mimeTypes; | ||
$pathOperation['summary'] ?? $pathOperation['summary'] = sprintf('Replaces the %s resource.', $resourceShortName); | ||
$pathOperation['parameters'] ?? $pathOperation['parameters'] = [ | ||
[ | ||
'name' => 'id', | ||
'in' => 'path', | ||
'type' => 'string', | ||
'required' => true, | ||
], | ||
$pathOperation['parameters'] ?? $pathOperation['parameters'] = array_merge($this->getPathParameters($resourceClass), [ | ||
[ | ||
'name' => lcfirst($resourceShortName), | ||
'in' => 'body', | ||
|
@@ -391,7 +431,8 @@ private function updatePutOperation(\ArrayObject $pathOperation, array $mimeType | |
$this->getSerializerContext($operationType, true, $resourceMetadata, $operationName) | ||
))], | ||
], | ||
]; | ||
]); | ||
|
||
$pathOperation['responses'] ?? $pathOperation['responses'] = [ | ||
'200' => [ | ||
'description' => sprintf('%s resource updated', $resourceShortName), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,7 @@ | |
use Symfony\Component\Serializer\NameConverter\NameConverterInterface; | ||
|
||
/** | ||
* @author Philippe Guilbault <philippe.guilbault@gmail.com> | ||
* @author Amrouche Hamza <hamza.simperfit@gmail.com> | ||
* @author Kévin Dunglas <dunglas@gmail.com> | ||
*/ | ||
|
@@ -1823,4 +1824,129 @@ public function testNormalizeWithSubResource() | |
|
||
$this->assertEquals($expected, $normalizer->normalize($documentation)); | ||
} | ||
|
||
/** | ||
* | ||
* @group legacy | ||
* @expectedDeprecation Passing an instance of ApiPlatform\Core\Api\UrlGeneratorInterface to ApiPlatform\Core\Swagger\Serializer\DocumentationNormalizer::__construct() is deprecated since version 2.1 and will be removed in 3.0. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove these annotations and fix the constructor instead. |
||
*/ | ||
public function testNormalizeWithIdentifierName() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a test with composite identifiers? |
||
{ | ||
$documentation = new Documentation(new ResourceNameCollection([Dummy::class]), '', '', '0.0.0', ['jsonld' => ['application/ld+json']]); | ||
|
||
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); | ||
$propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->shouldBeCalled()->willReturn(new PropertyNameCollection(['id', 'name', 'description'])); | ||
|
||
$dummyMetadata = new ResourceMetadata( | ||
'Dummy', | ||
'This is a dummy.', | ||
'http://schema.example.com/Dummy', | ||
['get' => ['method' => 'GET']], | ||
[], | ||
[] | ||
); | ||
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); | ||
$resourceMetadataFactoryProphecy->create(Dummy::class)->shouldBeCalled()->willReturn($dummyMetadata); | ||
|
||
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); | ||
$propertyMetadataFactoryProphecy->create(Dummy::class, 'id')->shouldBeCalled()->willReturn(new PropertyMetadata( | ||
new Type(Type::BUILTIN_TYPE_INT), | ||
'This is an id.', | ||
true, | ||
false, | ||
null, | ||
null, | ||
false | ||
)); | ||
$propertyMetadataFactoryProphecy->create(Dummy::class, 'name')->shouldBeCalled()->willReturn(new PropertyMetadata( | ||
new Type(Type::BUILTIN_TYPE_STRING), | ||
'This is a name.', | ||
true, | ||
false, | ||
null, | ||
null, | ||
true, | ||
true | ||
)); | ||
$propertyMetadataFactoryProphecy->create(Dummy::class, 'description')->shouldBeCalled()->willReturn(new PropertyMetadata( | ||
new Type(Type::BUILTIN_TYPE_STRING), | ||
'This is a description.', | ||
true, | ||
true | ||
)); | ||
|
||
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); | ||
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true); | ||
|
||
$operationMethodResolverProphecy = $this->prophesize(OperationMethodResolverInterface::class); | ||
$operationMethodResolverProphecy->getItemOperationMethod(Dummy::class, 'get')->shouldBeCalled()->willReturn('GET'); | ||
|
||
$urlGeneratorProphecy = $this->prophesize(UrlGeneratorInterface::class); | ||
|
||
$operationPathResolver = new CustomOperationPathResolver(new UnderscoreOperationPathResolver()); | ||
|
||
$normalizer = new DocumentationNormalizer( | ||
$resourceMetadataFactoryProphecy->reveal(), | ||
$propertyNameCollectionFactoryProphecy->reveal(), | ||
$propertyMetadataFactoryProphecy->reveal(), | ||
$resourceClassResolverProphecy->reveal(), | ||
$operationMethodResolverProphecy->reveal(), | ||
$operationPathResolver, | ||
$urlGeneratorProphecy->reveal() | ||
); | ||
|
||
$expected = array ( | ||
'swagger' => '2.0', | ||
'basePath' => '/', | ||
'info' => ['title' => '', 'version' => '0.0.0', ], | ||
'paths' => new \ArrayObject([ | ||
'/dummies/{id}' => [ | ||
'get' => new \ArrayObject([ | ||
'tags' => ['Dummy'], | ||
'operationId' => 'getDummyItem', | ||
'produces' => ['application/ld+json'], | ||
'summary' => 'Retrieves a Dummy resource.', | ||
'parameters' => [[ | ||
'name' => 'name', | ||
'type' => 'string', | ||
'in' => 'path', | ||
'required' => true, | ||
]], | ||
'responses' => [ | ||
200 => [ | ||
'description' => 'Dummy resource response', | ||
'schema' => ['$ref' => '#/definitions/Dummy'], | ||
], | ||
404 => ['description' => 'Resource not found'], | ||
], | ||
]), | ||
], | ||
]), | ||
'definitions' => new \ArrayObject([ | ||
'Dummy' => new \ArrayObject([ | ||
'type' => 'object', | ||
'description' => 'This is a dummy.', | ||
'externalDocs' => ['url' => 'http://schema.example.com/Dummy'], | ||
'properties' => [ | ||
'id' => new \ArrayObject([ | ||
'readOnly' => true, | ||
'description' => 'This is an id.', | ||
'type' => 'integer', | ||
]), | ||
'name' => new \ArrayObject([ | ||
'readOnly' => true, | ||
'description' => 'This is a name.', | ||
'type' => 'string', | ||
]), | ||
'description' => new \ArrayObject([ | ||
'description' => 'This is a description.', | ||
'type' => 'string', | ||
]), | ||
], | ||
]), | ||
]), | ||
); | ||
|
||
$this->assertEquals($expected, $normalizer->normalize($documentation)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$identifiers
instead of$properties
?