Skip to content

Commit 81f819b

Browse files
authored
Merge pull request #3123 from maks-rafalko/bugfix/aboid-miltiple-body-parameters
Do not append `body` parameter if it already exists
2 parents 83cd888 + ddfec09 commit 81f819b

File tree

2 files changed

+213
-5
lines changed

2 files changed

+213
-5
lines changed

src/Swagger/Serializer/DocumentationNormalizer.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -543,15 +543,28 @@ private function addRequestBody(bool $v3, \ArrayObject $pathOperation, \ArrayObj
543543
return $pathOperation;
544544
}
545545

546-
$pathOperation['parameters'][] = [
547-
'name' => lcfirst($resourceShortName),
548-
'in' => 'body',
549-
'description' => $description,
550-
] + $message;
546+
if (!$this->hasBodyParameter($pathOperation['parameters'] ?? [])) {
547+
$pathOperation['parameters'][] = [
548+
'name' => lcfirst($resourceShortName),
549+
'in' => 'body',
550+
'description' => $description,
551+
] + $message;
552+
}
551553

552554
return $pathOperation;
553555
}
554556

557+
private function hasBodyParameter(array $parameters): bool
558+
{
559+
foreach ($parameters as $parameter) {
560+
if (\array_key_exists('in', $parameter) && 'body' === $parameter['in']) {
561+
return true;
562+
}
563+
}
564+
565+
return false;
566+
}
567+
555568
private function updateDeleteOperation(bool $v3, \ArrayObject $pathOperation, string $resourceShortName, string $operationType, string $operationName, ResourceMetadata $resourceMetadata): \ArrayObject
556569
{
557570
$pathOperation['summary'] ?? $pathOperation['summary'] = sprintf('Removes the %s resource.', $resourceShortName);

tests/Swagger/Serializer/DocumentationNormalizerV2Test.php

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,201 @@ public function testNormalizeWithOnlyNormalizationGroups(): void
803803
$this->assertEquals($expected, $normalizer->normalize($documentation));
804804
}
805805

806+
public function testNormalizeNotAddExtraBodyParameters(): void
807+
{
808+
$title = 'Test API';
809+
$description = 'This is a test API.';
810+
$version = '1.2.3';
811+
$documentation = new Documentation(new ResourceNameCollection([Dummy::class]), $title, $description, $version);
812+
$groups = ['dummy', 'foo', 'bar'];
813+
814+
$ref = 'Dummy-'.implode('_', $groups);
815+
816+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
817+
$propertyNameCollectionFactoryProphecy->create(Dummy::class, ['serializer_groups' => $groups])->shouldBeCalledTimes(1)->willReturn(new PropertyNameCollection(['gerard']));
818+
$propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->shouldBeCalled()->willReturn(new PropertyNameCollection(['name']));
819+
820+
$dummyMetadata = new ResourceMetadata(
821+
'Dummy',
822+
'This is a dummy.',
823+
'http://schema.example.com/Dummy',
824+
[
825+
'get' => ['method' => 'GET'] + self::OPERATION_FORMATS,
826+
'put' => ['method' => 'PUT', 'normalization_context' => [AbstractNormalizer::GROUPS => $groups]] + self::OPERATION_FORMATS,
827+
],
828+
[
829+
'get' => ['method' => 'GET'] + self::OPERATION_FORMATS,
830+
'post' => [
831+
'method' => 'POST',
832+
'swagger_context' => [
833+
'parameters' => [
834+
[
835+
'name' => 'dummy',
836+
'in' => 'body',
837+
'description' => 'The new custom Dummy resource',
838+
'schema' => ['$ref' => '#/definitions/Dummy'],
839+
],
840+
],
841+
],
842+
] + self::OPERATION_FORMATS,
843+
]
844+
);
845+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
846+
$resourceMetadataFactoryProphecy->create(Dummy::class)->shouldBeCalled()->willReturn($dummyMetadata);
847+
848+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
849+
$propertyMetadataFactoryProphecy->create(Dummy::class, 'name')->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'This is a name.', true, true, true, true, false, false, null, null, []));
850+
$propertyMetadataFactoryProphecy->create(Dummy::class, 'gerard')->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'This is a gerard.', true, true, true, true, false, false, null, null, []));
851+
852+
$operationPathResolver = new CustomOperationPathResolver(new OperationPathResolver(new UnderscorePathSegmentNameGenerator()));
853+
854+
$normalizer = new DocumentationNormalizer(
855+
$resourceMetadataFactoryProphecy->reveal(),
856+
$propertyNameCollectionFactoryProphecy->reveal(),
857+
$propertyMetadataFactoryProphecy->reveal(),
858+
null,
859+
null,
860+
$operationPathResolver
861+
);
862+
863+
$expected = [
864+
'swagger' => '2.0',
865+
'basePath' => '/',
866+
'info' => [
867+
'title' => 'Test API',
868+
'description' => 'This is a test API.',
869+
'version' => '1.2.3',
870+
],
871+
'paths' => new \ArrayObject([
872+
'/dummies' => [
873+
'get' => new \ArrayObject([
874+
'tags' => [
875+
'Dummy',
876+
],
877+
'operationId' => 'getDummyCollection',
878+
'produces' => ['application/ld+json'],
879+
'summary' => 'Retrieves the collection of Dummy resources.',
880+
'parameters' => [
881+
[
882+
'name' => 'page',
883+
'in' => 'query',
884+
'required' => false,
885+
'type' => 'integer',
886+
'description' => 'The collection page number',
887+
],
888+
],
889+
'responses' => [
890+
200 => [
891+
'description' => 'Dummy collection response',
892+
'schema' => [
893+
'type' => 'array',
894+
'items' => ['$ref' => '#/definitions/Dummy'],
895+
],
896+
],
897+
],
898+
]),
899+
'post' => new \ArrayObject([
900+
'tags' => ['Dummy'],
901+
'operationId' => 'postDummyCollection',
902+
'consumes' => ['application/ld+json'],
903+
'produces' => ['application/ld+json'],
904+
'summary' => 'Creates a Dummy resource.',
905+
'parameters' => [[
906+
'name' => 'dummy',
907+
'in' => 'body',
908+
'description' => 'The new custom Dummy resource',
909+
'schema' => ['$ref' => '#/definitions/Dummy'],
910+
]],
911+
'responses' => [
912+
201 => [
913+
'description' => 'Dummy resource created',
914+
'schema' => ['$ref' => '#/definitions/Dummy'],
915+
],
916+
400 => ['description' => 'Invalid input'],
917+
404 => ['description' => 'Resource not found'],
918+
],
919+
]),
920+
],
921+
'/dummies/{id}' => [
922+
'get' => new \ArrayObject([
923+
'tags' => ['Dummy'],
924+
'operationId' => 'getDummyItem',
925+
'produces' => ['application/ld+json'],
926+
'summary' => 'Retrieves a Dummy resource.',
927+
'parameters' => [[
928+
'name' => 'id',
929+
'in' => 'path',
930+
'type' => 'string',
931+
'required' => true,
932+
]],
933+
'responses' => [
934+
200 => [
935+
'description' => 'Dummy resource response',
936+
'schema' => ['$ref' => '#/definitions/Dummy'],
937+
],
938+
404 => ['description' => 'Resource not found'],
939+
],
940+
]),
941+
'put' => new \ArrayObject([
942+
'tags' => ['Dummy'],
943+
'operationId' => 'putDummyItem',
944+
'consumes' => ['application/ld+json'],
945+
'produces' => ['application/ld+json'],
946+
'summary' => 'Replaces the Dummy resource.',
947+
'parameters' => [
948+
[
949+
'name' => 'id',
950+
'in' => 'path',
951+
'type' => 'string',
952+
'required' => true,
953+
],
954+
[
955+
'name' => 'dummy',
956+
'in' => 'body',
957+
'description' => 'The updated Dummy resource',
958+
'schema' => ['$ref' => '#/definitions/Dummy'],
959+
],
960+
],
961+
'responses' => [
962+
200 => [
963+
'description' => 'Dummy resource updated',
964+
'schema' => ['$ref' => '#/definitions/'.$ref],
965+
],
966+
400 => ['description' => 'Invalid input'],
967+
404 => ['description' => 'Resource not found'],
968+
],
969+
]),
970+
],
971+
]),
972+
'definitions' => new \ArrayObject([
973+
'Dummy' => new \ArrayObject([
974+
'type' => 'object',
975+
'description' => 'This is a dummy.',
976+
'externalDocs' => ['url' => 'http://schema.example.com/Dummy'],
977+
'properties' => [
978+
'name' => new \ArrayObject([
979+
'type' => 'string',
980+
'description' => 'This is a name.',
981+
]),
982+
],
983+
]),
984+
$ref => new \ArrayObject([
985+
'type' => 'object',
986+
'description' => 'This is a dummy.',
987+
'externalDocs' => ['url' => 'http://schema.example.com/Dummy'],
988+
'properties' => [
989+
'gerard' => new \ArrayObject([
990+
'type' => 'string',
991+
'description' => 'This is a gerard.',
992+
]),
993+
],
994+
]),
995+
]),
996+
];
997+
998+
$this->assertEquals($expected, $normalizer->normalize($documentation));
999+
}
1000+
8061001
public function testNormalizeWithSwaggerDefinitionName(): void
8071002
{
8081003
$documentation = new Documentation(new ResourceNameCollection([Dummy::class]), 'Test API', 'This is a test API.', '1.2.3');

0 commit comments

Comments
 (0)