Skip to content

Commit c5a81e2

Browse files
fix(jsonschema): declare output properties as required
1 parent eb6396b commit c5a81e2

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

src/JsonSchema/SchemaFactory.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ public function buildSchema(string $className, string $format = 'json', string $
8383

8484
$validationGroups = $operation ? $this->getValidationGroups($operation) : [];
8585
$version = $schema->getVersion();
86+
8687
$definitionName = $this->definitionNameFactory->create($className, $format, $inputOrOutputClass, $operation, $serializerContext);
88+
$definitionName .= '.'.$type;
89+
8790
$method = $operation instanceof HttpOperation ? $operation->getMethod() : 'GET';
8891
if (!$operation) {
8992
$method = Schema::TYPE_INPUT === $type ? 'POST' : 'GET';
@@ -143,12 +146,18 @@ public function buildSchema(string $className, string $format = 'json', string $
143146
foreach ($this->propertyNameCollectionFactory->create($inputOrOutputClass, $options) as $propertyName) {
144147
$propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName, $options);
145148

146-
if (false === $propertyMetadata->isReadable() && false === $propertyMetadata->isWritable()) {
149+
if (
150+
Schema::TYPE_INPUT === $type && false === $propertyMetadata->isWritable()
151+
|| Schema::TYPE_OUTPUT === $type && false === $propertyMetadata->isReadable()
152+
) {
147153
continue;
148154
}
149155

150156
$normalizedPropertyName = $this->nameConverter ? $this->nameConverter->normalize($propertyName, $inputOrOutputClass, $format, $serializerContext) : $propertyName;
151-
if ($propertyMetadata->isRequired() && !$isJsonMergePatch) {
157+
158+
// Property should be considered as required for output since they are "always" in the response body.
159+
// @see https://github.com/api-platform/core/issues/7457
160+
if (Schema::TYPE_OUTPUT === $type || $propertyMetadata->isRequired() && !$isJsonMergePatch) {
152161
$definition['required'][] = $normalizedPropertyName;
153162
}
154163

tests/Functional/JsonSchema/JsonLdJsonSchemaTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public function testSubSchemaJsonLd(): void
8181
'$ref' => '#/definitions/TestEntity.jsonld-read',
8282
]),
8383
],
84+
'required' => ['id', 'description', 'tests', 'nonResourceTests', 'type'],
8485
]),
8586
],
8687
]);
@@ -105,6 +106,7 @@ public function testSubSchemaJsonLd(): void
105106
],
106107
]),
107108
],
109+
'required' => ['id', 'nullableString', 'nullableInt'],
108110
]);
109111

110112
$expectedTestEntitySchema = new \ArrayObject([
@@ -132,6 +134,7 @@ public function testSubSchemaJsonLd(): void
132134
],
133135
]),
134136
],
137+
'required' => ['id', 'nullableString', 'nullableInt'],
135138
]),
136139
],
137140
]);

tests/Functional/OpenApiTest.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public function testErrorsAreDocumented(): void
138138
['$ref' => '#/components/schemas/HydraItemBaseSchema'],
139139
[
140140
'type' => 'object',
141+
'required' => ['title', 'detail', 'status', 'instance', 'type', 'description'],
141142
'properties' => [
142143
'title' => [
143144
'readOnly' => true,
@@ -243,6 +244,7 @@ public function testHasSchemasForMultipleFormats(): void
243244
['$ref' => '#/components/schemas/HydraItemBaseSchema'],
244245
[
245246
'type' => 'object',
247+
'required' => ['id'],
246248
'properties' => [
247249
'id' => ['type' => 'string'],
248250
],
@@ -326,7 +328,25 @@ public function testRetrieveTheOpenApiDocumentation(): void
326328
$this->assertArrayHasKey('put', $json['paths']['/api/custom-call/{id}']);
327329

328330
$this->assertArrayHasKey('id', $json['components']['schemas']['Dummy']['properties']);
329-
$this->assertSame(['name'], $json['components']['schemas']['Dummy']['required']);
331+
$this->assertSame([
332+
'id',
333+
'name',
334+
'alias',
335+
'foo',
336+
'description',
337+
'dummy',
338+
'dummyBoolean',
339+
'dummyDate',
340+
'dummyFloat',
341+
'dummyPrice',
342+
'relatedDummy',
343+
'relatedDummies',
344+
'jsonData',
345+
'arrayData',
346+
'name_converted',
347+
'relatedOwnedDummy',
348+
'relatedOwningDummy',
349+
], $json['components']['schemas']['Dummy']['required']);
330350
$this->assertArrayHasKey('genderType', $json['components']['schemas']['Person']['properties']);
331351
$this->assertEquals([
332352
'default' => 'male',

0 commit comments

Comments
 (0)