diff --git a/src/JsonSchema/SchemaFactory.php b/src/JsonSchema/SchemaFactory.php index bfbf57b4d1..d2db0a5040 100644 --- a/src/JsonSchema/SchemaFactory.php +++ b/src/JsonSchema/SchemaFactory.php @@ -83,7 +83,10 @@ public function buildSchema(string $className, string $format = 'json', string $ $validationGroups = $operation ? $this->getValidationGroups($operation) : []; $version = $schema->getVersion(); + $definitionName = $this->definitionNameFactory->create($className, $format, $inputOrOutputClass, $operation, $serializerContext); + $definitionName .= '.'.$type; + $method = $operation instanceof HttpOperation ? $operation->getMethod() : 'GET'; if (!$operation) { $method = Schema::TYPE_INPUT === $type ? 'POST' : 'GET'; @@ -143,12 +146,18 @@ public function buildSchema(string $className, string $format = 'json', string $ foreach ($this->propertyNameCollectionFactory->create($inputOrOutputClass, $options) as $propertyName) { $propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName, $options); - if (false === $propertyMetadata->isReadable() && false === $propertyMetadata->isWritable()) { + if ( + Schema::TYPE_INPUT === $type && false === $propertyMetadata->isWritable() + || Schema::TYPE_OUTPUT === $type && false === $propertyMetadata->isReadable() + ) { continue; } $normalizedPropertyName = $this->nameConverter ? $this->nameConverter->normalize($propertyName, $inputOrOutputClass, $format, $serializerContext) : $propertyName; - if ($propertyMetadata->isRequired() && !$isJsonMergePatch) { + + // Property should be considered as required for output since they are "always" in the response body. + // @see https://github.com/api-platform/core/issues/7457 + if (Schema::TYPE_OUTPUT === $type || $propertyMetadata->isRequired() && !$isJsonMergePatch) { $definition['required'][] = $normalizedPropertyName; } diff --git a/tests/Functional/JsonSchema/JsonLdJsonSchemaTest.php b/tests/Functional/JsonSchema/JsonLdJsonSchemaTest.php index b1380c4ec7..8e83c6e0ba 100644 --- a/tests/Functional/JsonSchema/JsonLdJsonSchemaTest.php +++ b/tests/Functional/JsonSchema/JsonLdJsonSchemaTest.php @@ -81,6 +81,7 @@ public function testSubSchemaJsonLd(): void '$ref' => '#/definitions/TestEntity.jsonld-read', ]), ], + 'required' => ['id', 'description', 'tests', 'nonResourceTests', 'type'], ]), ], ]); @@ -105,6 +106,7 @@ public function testSubSchemaJsonLd(): void ], ]), ], + 'required' => ['id', 'nullableString', 'nullableInt'], ]); $expectedTestEntitySchema = new \ArrayObject([ @@ -132,6 +134,7 @@ public function testSubSchemaJsonLd(): void ], ]), ], + 'required' => ['id', 'nullableString', 'nullableInt'], ]), ], ]); diff --git a/tests/Functional/OpenApiTest.php b/tests/Functional/OpenApiTest.php index 6912d7154d..e251965259 100644 --- a/tests/Functional/OpenApiTest.php +++ b/tests/Functional/OpenApiTest.php @@ -138,6 +138,7 @@ public function testErrorsAreDocumented(): void ['$ref' => '#/components/schemas/HydraItemBaseSchema'], [ 'type' => 'object', + 'required' => ['title', 'detail', 'status', 'instance', 'type', 'description'], 'properties' => [ 'title' => [ 'readOnly' => true, @@ -243,6 +244,7 @@ public function testHasSchemasForMultipleFormats(): void ['$ref' => '#/components/schemas/HydraItemBaseSchema'], [ 'type' => 'object', + 'required' => ['id'], 'properties' => [ 'id' => ['type' => 'string'], ], @@ -326,7 +328,25 @@ public function testRetrieveTheOpenApiDocumentation(): void $this->assertArrayHasKey('put', $json['paths']['/api/custom-call/{id}']); $this->assertArrayHasKey('id', $json['components']['schemas']['Dummy']['properties']); - $this->assertSame(['name'], $json['components']['schemas']['Dummy']['required']); + $this->assertSame([ + 'id', + 'name', + 'alias', + 'foo', + 'description', + 'dummy', + 'dummyBoolean', + 'dummyDate', + 'dummyFloat', + 'dummyPrice', + 'relatedDummy', + 'relatedDummies', + 'jsonData', + 'arrayData', + 'name_converted', + 'relatedOwnedDummy', + 'relatedOwningDummy', + ], $json['components']['schemas']['Dummy']['required']); $this->assertArrayHasKey('genderType', $json['components']['schemas']['Person']['properties']); $this->assertEquals([ 'default' => 'male',