From 55ee6f40b167232ad7ff474d6c4ab80c254e69ec Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sun, 29 Oct 2023 03:17:57 +0100 Subject: [PATCH 1/7] Fixed: the 'first' link should not be required, because JsonApiDotNetCore omits it when no resources are returned --- .../JsonApiObjects/Links/LinksInResourceCollectionDocument.cs | 1 - .../Links/LinksInResourceIdentifierCollectionDocument.cs | 1 - test/OpenApiClientTests/LegacyClient/swagger.g.json | 4 ---- .../NamingConventions/CamelCase/swagger.g.json | 4 ---- .../NamingConventions/KebabCase/swagger.g.json | 4 ---- .../NamingConventions/PascalCase/swagger.g.json | 4 ---- .../ModelStateValidationOff/swagger.g.json | 4 ---- .../ModelStateValidationOn/swagger.g.json | 4 ---- .../ModelStateValidationOff/swagger.g.json | 4 ---- .../ModelStateValidationOn/swagger.g.json | 4 ---- test/OpenApiTests/LegacyOpenApiIntegration/swagger.json | 4 ---- 11 files changed, 38 deletions(-) diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs index 9ce49f9f58..ee9c9d31df 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs @@ -14,7 +14,6 @@ internal sealed class LinksInResourceCollectionDocument [JsonPropertyName("describedby")] public string Describedby { get; set; } = null!; - [Required] [JsonPropertyName("first")] public string First { get; set; } = null!; diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs index 839dde99b8..ca32345e55 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs @@ -18,7 +18,6 @@ internal sealed class LinksInResourceIdentifierCollectionDocument [JsonPropertyName("describedby")] public string Describedby { get; set; } = null!; - [Required] [JsonPropertyName("first")] public string First { get; set; } = null!; diff --git a/test/OpenApiClientTests/LegacyClient/swagger.g.json b/test/OpenApiClientTests/LegacyClient/swagger.g.json index e95d8261b4..02f1a73f30 100644 --- a/test/OpenApiClientTests/LegacyClient/swagger.g.json +++ b/test/OpenApiClientTests/LegacyClient/swagger.g.json @@ -3697,7 +3697,6 @@ }, "links-in-resource-collection-document": { "required": [ - "first", "self" ], "type": "object", @@ -3710,7 +3709,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -3743,7 +3741,6 @@ }, "links-in-resource-identifier-collection-document": { "required": [ - "first", "related", "self" ], @@ -3761,7 +3758,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json index 148b2203bd..db86af513e 100644 --- a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json @@ -905,7 +905,6 @@ }, "linksInResourceCollectionDocument": { "required": [ - "first", "self" ], "type": "object", @@ -918,7 +917,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -951,7 +949,6 @@ }, "linksInResourceIdentifierCollectionDocument": { "required": [ - "first", "related", "self" ], @@ -969,7 +966,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json index d439357cae..10d2e1b4bb 100644 --- a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json @@ -905,7 +905,6 @@ }, "links-in-resource-collection-document": { "required": [ - "first", "self" ], "type": "object", @@ -918,7 +917,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -951,7 +949,6 @@ }, "links-in-resource-identifier-collection-document": { "required": [ - "first", "related", "self" ], @@ -969,7 +966,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json index ed70846149..81f2ad06f9 100644 --- a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json @@ -905,7 +905,6 @@ }, "LinksInResourceCollectionDocument": { "required": [ - "first", "self" ], "type": "object", @@ -918,7 +917,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -951,7 +949,6 @@ }, "LinksInResourceIdentifierCollectionDocument": { "required": [ - "first", "related", "self" ], @@ -969,7 +966,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json index 993604786b..30c3bee2b4 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json @@ -1288,7 +1288,6 @@ }, "linksInResourceCollectionDocument": { "required": [ - "first", "self" ], "type": "object", @@ -1301,7 +1300,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -1334,7 +1332,6 @@ }, "linksInResourceIdentifierCollectionDocument": { "required": [ - "first", "related", "self" ], @@ -1352,7 +1349,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json index 3cd727b975..e41c9e52f6 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json @@ -1344,7 +1344,6 @@ }, "linksInResourceCollectionDocument": { "required": [ - "first", "self" ], "type": "object", @@ -1357,7 +1356,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -1390,7 +1388,6 @@ }, "linksInResourceIdentifierCollectionDocument": { "required": [ - "first", "related", "self" ], @@ -1408,7 +1405,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json index 8f117b6f84..57d07d83e2 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json @@ -1694,7 +1694,6 @@ }, "linksInResourceCollectionDocument": { "required": [ - "first", "self" ], "type": "object", @@ -1707,7 +1706,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -1740,7 +1738,6 @@ }, "linksInResourceIdentifierCollectionDocument": { "required": [ - "first", "related", "self" ], @@ -1758,7 +1755,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json index 7df69520b9..f430fc961f 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json @@ -1694,7 +1694,6 @@ }, "linksInResourceCollectionDocument": { "required": [ - "first", "self" ], "type": "object", @@ -1707,7 +1706,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -1740,7 +1738,6 @@ }, "linksInResourceIdentifierCollectionDocument": { "required": [ - "first", "related", "self" ], @@ -1758,7 +1755,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json index e95d8261b4..02f1a73f30 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json +++ b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json @@ -3697,7 +3697,6 @@ }, "links-in-resource-collection-document": { "required": [ - "first", "self" ], "type": "object", @@ -3710,7 +3709,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -3743,7 +3741,6 @@ }, "links-in-resource-identifier-collection-document": { "required": [ - "first", "related", "self" ], @@ -3761,7 +3758,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { From fab05c879654fa50d8203dff6d11098ddc09b885 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sun, 29 Oct 2023 03:22:30 +0100 Subject: [PATCH 2/7] Fixed: do not generate duplicate operation ID when secondary resource type is same as primary resource type at secondary endpoint --- .../JsonApiOperationIdSelector.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs index 507cd26e59..2da76a3931 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs @@ -56,14 +56,14 @@ public string GetOperationId(ApiDescription endpoint) throw new UnreachableCodeException(); } - string template = GetTemplate(primaryResourceType.ClrType, endpoint); + string template = GetTemplate(endpoint); return ApplyTemplate(template, primaryResourceType, endpoint); } - private static string GetTemplate(Type resourceClrType, ApiDescription endpoint) + private static string GetTemplate(ApiDescription endpoint) { - Type requestDocumentType = GetDocumentType(resourceClrType, endpoint); + Type requestDocumentType = GetDocumentType(endpoint); if (!DocumentOpenTypeToOperationIdTemplateMap.TryGetValue(requestDocumentType, out string? template)) { @@ -73,7 +73,7 @@ private static string GetTemplate(Type resourceClrType, ApiDescription endpoint) return template; } - private static Type GetDocumentType(Type primaryResourceClrType, ApiDescription endpoint) + private static Type GetDocumentType(ApiDescription endpoint) { var producesResponseTypeAttribute = endpoint.ActionDescriptor.GetFilterMetadata(); @@ -87,14 +87,9 @@ private static Type GetDocumentType(Type primaryResourceClrType, ApiDescription Type documentType = requestBodyDescriptor?.ParameterType.GetGenericTypeDefinition() ?? GetGenericTypeDefinition(producesResponseTypeAttribute.Type) ?? producesResponseTypeAttribute.Type; - if (documentType == typeof(ResourceCollectionResponseDocument<>)) + if (documentType == typeof(ResourceCollectionResponseDocument<>) && endpoint.ParameterDescriptions.Count > 0) { - Type documentResourceType = producesResponseTypeAttribute.Type.GetGenericArguments()[0]; - - if (documentResourceType != primaryResourceClrType) - { - documentType = typeof(SecondaryResourceResponseDocument<>); - } + documentType = typeof(SecondaryResourceResponseDocument<>); } return documentType; From 6d503995637f1cb1ad3bbe91d2d0bb1b516402fa Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sun, 29 Oct 2023 17:49:02 +0100 Subject: [PATCH 3/7] Fixed: resource fields are never required in response objects (sparse fieldsets may exclude them) --- .../ResourceFieldObjectSchemaBuilder.cs | 5 ++--- .../OpenApiClientTests/LegacyClient/swagger.g.json | 14 -------------- .../NamingConventions/CamelCase/swagger.g.json | 9 --------- .../NamingConventions/KebabCase/swagger.g.json | 9 --------- .../NamingConventions/PascalCase/swagger.g.json | 9 --------- .../ModelStateValidationOff/swagger.g.json | 9 --------- .../ModelStateValidationOn/swagger.g.json | 7 ------- .../ModelStateValidationOff/swagger.g.json | 11 ----------- .../ModelStateValidationOn/swagger.g.json | 11 ----------- .../LegacyOpenApiIntegration/swagger.json | 14 -------------- 10 files changed, 2 insertions(+), 96 deletions(-) diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs index 4011c357ac..e77a724bef 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs @@ -145,9 +145,8 @@ private Type GetRepresentedTypeForAttributeSchema(AttrAttribute attribute) private bool IsFieldRequired(ResourceFieldAttribute field) { - bool isSchemaForUpdateResourceEndpoint = _resourceTypeInfo.ResourceObjectOpenType == typeof(ResourceObjectInPatchRequest<>); - - return !isSchemaForUpdateResourceEndpoint && _resourceFieldValidationMetadataProvider.IsRequired(field); + bool isSchemaForPostResourceRequest = _resourceTypeInfo.ResourceObjectOpenType == typeof(ResourceObjectInPostRequest<>); + return isSchemaForPostResourceRequest && _resourceFieldValidationMetadataProvider.IsRequired(field); } public void SetMembersOfRelationshipsObject(OpenApiSchema fullSchemaForRelationshipsObject) diff --git a/test/OpenApiClientTests/LegacyClient/swagger.g.json b/test/OpenApiClientTests/LegacyClient/swagger.g.json index 02f1a73f30..6042d7be81 100644 --- a/test/OpenApiClientTests/LegacyClient/swagger.g.json +++ b/test/OpenApiClientTests/LegacyClient/swagger.g.json @@ -2425,9 +2425,6 @@ "additionalProperties": false }, "airplane-attributes-in-response": { - "required": [ - "name" - ], "type": "object", "properties": { "name": { @@ -2781,10 +2778,6 @@ "additionalProperties": false }, "flight-attendant-attributes-in-response": { - "required": [ - "email-address", - "profile-image-url" - ], "type": "object", "properties": { "email-address": { @@ -3236,10 +3229,6 @@ "additionalProperties": false }, "flight-attributes-in-response": { - "required": [ - "final-destination", - "services-on-board" - ], "type": "object", "properties": { "final-destination": { @@ -3610,9 +3599,6 @@ "additionalProperties": false }, "flight-relationships-in-response": { - "required": [ - "purser" - ], "type": "object", "properties": { "cabin-crew-members": { diff --git a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json index db86af513e..7c935d1d30 100644 --- a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json @@ -1132,9 +1132,6 @@ "additionalProperties": false }, "staffMemberAttributesInResponse": { - "required": [ - "name" - ], "type": "object", "properties": { "name": { @@ -1388,9 +1385,6 @@ "additionalProperties": false }, "supermarketAttributesInResponse": { - "required": [ - "nameOfCity" - ], "type": "object", "properties": { "nameOfCity": { @@ -1677,9 +1671,6 @@ "additionalProperties": false }, "supermarketRelationshipsInResponse": { - "required": [ - "storeManager" - ], "type": "object", "properties": { "storeManager": { diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json index 10d2e1b4bb..a182e7f9aa 100644 --- a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json @@ -1132,9 +1132,6 @@ "additionalProperties": false }, "staff-member-attributes-in-response": { - "required": [ - "name" - ], "type": "object", "properties": { "name": { @@ -1388,9 +1385,6 @@ "additionalProperties": false }, "supermarket-attributes-in-response": { - "required": [ - "name-of-city" - ], "type": "object", "properties": { "name-of-city": { @@ -1677,9 +1671,6 @@ "additionalProperties": false }, "supermarket-relationships-in-response": { - "required": [ - "store-manager" - ], "type": "object", "properties": { "store-manager": { diff --git a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json index 81f2ad06f9..d10af305bc 100644 --- a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json @@ -1132,9 +1132,6 @@ "additionalProperties": false }, "StaffMemberAttributesInResponse": { - "required": [ - "Name" - ], "type": "object", "properties": { "Name": { @@ -1388,9 +1385,6 @@ "additionalProperties": false }, "SupermarketAttributesInResponse": { - "required": [ - "NameOfCity" - ], "type": "object", "properties": { "NameOfCity": { @@ -1677,9 +1671,6 @@ "additionalProperties": false }, "SupermarketRelationshipsInResponse": { - "required": [ - "StoreManager" - ], "type": "object", "properties": { "StoreManager": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json index 30c3bee2b4..7479ee14e4 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json @@ -1572,11 +1572,6 @@ "additionalProperties": false }, "resourceAttributesInResponse": { - "required": [ - "requiredNullableValueType", - "requiredReferenceType", - "requiredValueType" - ], "type": "object", "properties": { "referenceType": { @@ -1881,10 +1876,6 @@ "additionalProperties": false }, "resourceRelationshipsInResponse": { - "required": [ - "requiredToMany", - "requiredToOne" - ], "type": "object", "properties": { "toOne": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json index e41c9e52f6..960af45209 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json @@ -1623,10 +1623,6 @@ "additionalProperties": false }, "resourceAttributesInResponse": { - "required": [ - "requiredNullableValueType", - "requiredReferenceType" - ], "type": "object", "properties": { "referenceType": { @@ -1928,9 +1924,6 @@ "additionalProperties": false }, "resourceRelationshipsInResponse": { - "required": [ - "requiredToOne" - ], "type": "object", "properties": { "toOne": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json index 57d07d83e2..8e93abc1a9 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json @@ -1993,12 +1993,6 @@ "additionalProperties": false }, "resourceAttributesInResponse": { - "required": [ - "requiredNonNullableReferenceType", - "requiredNullableReferenceType", - "requiredNullableValueType", - "requiredValueType" - ], "type": "object", "properties": { "nonNullableReferenceType": { @@ -2339,11 +2333,6 @@ "additionalProperties": false }, "resourceRelationshipsInResponse": { - "required": [ - "requiredNonNullableToOne", - "requiredNullableToOne", - "requiredToMany" - ], "type": "object", "properties": { "nonNullableToOne": { diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json index f430fc961f..09942e918c 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json @@ -1989,12 +1989,6 @@ "additionalProperties": false }, "resourceAttributesInResponse": { - "required": [ - "nonNullableReferenceType", - "requiredNonNullableReferenceType", - "requiredNullableReferenceType", - "requiredNullableValueType" - ], "type": "object", "properties": { "nonNullableReferenceType": { @@ -2333,11 +2327,6 @@ "additionalProperties": false }, "resourceRelationshipsInResponse": { - "required": [ - "nonNullableToOne", - "requiredNonNullableToOne", - "requiredNullableToOne" - ], "type": "object", "properties": { "nonNullableToOne": { diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json index 02f1a73f30..6042d7be81 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json +++ b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json @@ -2425,9 +2425,6 @@ "additionalProperties": false }, "airplane-attributes-in-response": { - "required": [ - "name" - ], "type": "object", "properties": { "name": { @@ -2781,10 +2778,6 @@ "additionalProperties": false }, "flight-attendant-attributes-in-response": { - "required": [ - "email-address", - "profile-image-url" - ], "type": "object", "properties": { "email-address": { @@ -3236,10 +3229,6 @@ "additionalProperties": false }, "flight-attributes-in-response": { - "required": [ - "final-destination", - "services-on-board" - ], "type": "object", "properties": { "final-destination": { @@ -3610,9 +3599,6 @@ "additionalProperties": false }, "flight-relationships-in-response": { - "required": [ - "purser" - ], "type": "object", "properties": { "cabin-crew-members": { From 0a4be97ea771edd97f53d51e70c5814486562c6e Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sun, 29 Oct 2023 14:38:22 +0100 Subject: [PATCH 4/7] Publicly expose ApiResponse --- .../JsonApiDotNetCore.OpenApi.Client}/ApiResponse.cs | 7 ++++--- .../PartialAttributeSerializationLifetimeTests.cs | 1 + test/OpenApiClientTests/LegacyClient/RequestTests.cs | 1 + test/OpenApiClientTests/LegacyClient/ResponseTests.cs | 1 + .../ModelStateValidationOff/CreateResourceTests.cs | 1 + .../ModelStateValidationOff/UpdateResourceTests.cs | 1 + .../ModelStateValidationOn/CreateResourceTests.cs | 1 + .../ModelStateValidationOn/UpdateResourceTests.cs | 1 + .../ModelStateValidationOff/CreateResourceTests.cs | 1 + .../ModelStateValidationOff/UpdateResourceTests.cs | 1 + .../ModelStateValidationOn/CreateResourceTests.cs | 1 + .../ModelStateValidationOn/UpdateResourceTests.cs | 1 + 12 files changed, 15 insertions(+), 3 deletions(-) rename {test/OpenApiClientTests => src/JsonApiDotNetCore.OpenApi.Client}/ApiResponse.cs (83%) diff --git a/test/OpenApiClientTests/ApiResponse.cs b/src/JsonApiDotNetCore.OpenApi.Client/ApiResponse.cs similarity index 83% rename from test/OpenApiClientTests/ApiResponse.cs rename to src/JsonApiDotNetCore.OpenApi.Client/ApiResponse.cs index 10e9ecf6ca..a94e5062dc 100644 --- a/test/OpenApiClientTests/ApiResponse.cs +++ b/src/JsonApiDotNetCore.OpenApi.Client/ApiResponse.cs @@ -1,11 +1,12 @@ -using JsonApiDotNetCore.OpenApi.Client; +using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.Client.Exceptions; #pragma warning disable AV1008 // Class should not be static -namespace OpenApiClientTests; +namespace JsonApiDotNetCore.OpenApi.Client; -internal static class ApiResponse +[PublicAPI] +public static class ApiResponse { public static async Task TranslateAsync(Func> operation) where TResponse : class diff --git a/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs b/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs index be71dfa1e3..a5cb4cc434 100644 --- a/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs +++ b/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs @@ -1,5 +1,6 @@ using System.Net; using FluentAssertions; +using JsonApiDotNetCore.OpenApi.Client; using OpenApiClientTests.LegacyClient.GeneratedCode; using TestBuildingBlocks; using Xunit; diff --git a/test/OpenApiClientTests/LegacyClient/RequestTests.cs b/test/OpenApiClientTests/LegacyClient/RequestTests.cs index 628106f4d1..908cde4742 100644 --- a/test/OpenApiClientTests/LegacyClient/RequestTests.cs +++ b/test/OpenApiClientTests/LegacyClient/RequestTests.cs @@ -3,6 +3,7 @@ using FluentAssertions.Common; using FluentAssertions.Extensions; using JsonApiDotNetCore.Middleware; +using JsonApiDotNetCore.OpenApi.Client; using Microsoft.Net.Http.Headers; using OpenApiClientTests.LegacyClient.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs index 73f1a9d0e5..73669ba5fc 100644 --- a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs +++ b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs @@ -2,6 +2,7 @@ using System.Net; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using JsonApiDotNetCore.OpenApi.Client.Exceptions; using OpenApiClientTests.LegacyClient.GeneratedCode; using Xunit; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs index 684a961a1b..3d965583f4 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs @@ -3,6 +3,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOff.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs index baad3e94d6..b5dd28dd87 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs @@ -2,6 +2,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOff.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs index f6eb4c4f1e..674a5f75ca 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs @@ -3,6 +3,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOn.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs index 9d049df43b..770ca101f3 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs @@ -2,6 +2,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOff.ModelStateValidationOn.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs index ec143cb9ee..9bc4d70a76 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs @@ -3,6 +3,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOff.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs index f17e9e08d3..9e2f8a1164 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs @@ -2,6 +2,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOff.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs index b569c008ff..cf62bf4f10 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs @@ -3,6 +3,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOn.GeneratedCode; using TestBuildingBlocks; diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs index 11876a7a02..f0cc06f8e4 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs @@ -2,6 +2,7 @@ using System.Text.Json; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client; using Newtonsoft.Json; using OpenApiClientTests.ResourceFieldValidation.NullableReferenceTypesOn.ModelStateValidationOn.GeneratedCode; using TestBuildingBlocks; From abc9fff733baeb337e6e812c191e0295219073dd Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Sun, 29 Oct 2023 04:37:48 +0100 Subject: [PATCH 5/7] Add OpenAPI support for JSON:API query string parameters, introduce end-to-end tests --- docs/usage/openapi-client.md | 24 +- .../OpenAPIs/swagger.json | 2053 +++++++++++++---- .../JsonApiDotNetCoreExampleClient/Program.cs | 10 +- .../JsonApiOperationDocumentationFilter.cs | 68 +- ...tialAttributeSerializationLifetimeTests.cs | 24 +- .../LegacyClient/RequestTests.cs | 18 +- .../LegacyClient/ResponseTests.cs | 24 +- .../LegacyClient/swagger.g.json | 880 ++++++- .../CamelCase/swagger.g.json | 332 ++- .../KebabCase/swagger.g.json | 332 ++- .../PascalCase/swagger.g.json | 332 ++- .../CreateResourceTests.cs | 12 +- .../UpdateResourceTests.cs | 6 +- .../ModelStateValidationOff/swagger.g.json | 414 +++- .../CreateResourceTests.cs | 16 +- .../UpdateResourceTests.cs | 6 +- .../ModelStateValidationOn/swagger.g.json | 414 +++- .../CreateResourceTests.cs | 16 +- .../UpdateResourceTests.cs | 6 +- .../ModelStateValidationOff/swagger.g.json | 554 ++++- .../CreateResourceTests.cs | 16 +- .../UpdateResourceTests.cs | 6 +- .../ModelStateValidationOn/swagger.g.json | 554 ++++- .../OpenApiEndToEndTests.csproj | 31 + .../QueryStrings/FilterTests.cs | 153 ++ .../GeneratedCode/QueryStringsClient.cs | 62 + .../QueryStrings/PaginationTests.cs | 169 ++ .../QueryStrings/SortTests.cs | 146 ++ .../QueryStrings/SparseFieldSetTests.cs | 185 ++ .../QueryStrings/swagger.g.json | 1567 +++++++++++++ .../DocComments/DocCommentsStartup.cs | 3 +- .../DocComments/DocCommentsTests.cs | 124 +- .../LegacyOpenApiIntegration/swagger.json | 880 ++++++- test/OpenApiTests/OpenApiStartup.cs | 8 + test/OpenApiTests/QueryStrings/Node.cs | 22 + .../QueryStrings/QueryStringFakers.cs | 19 + .../QueryStrings/QueryStringTests.cs | 85 + .../QueryStrings/QueryStringsDbContext.cs | 16 + .../JsonElementAssertionExtensions.cs | 12 +- 39 files changed, 8705 insertions(+), 894 deletions(-) create mode 100644 test/OpenApiEndToEndTests/OpenApiEndToEndTests.csproj create mode 100644 test/OpenApiEndToEndTests/QueryStrings/FilterTests.cs create mode 100644 test/OpenApiEndToEndTests/QueryStrings/GeneratedCode/QueryStringsClient.cs create mode 100644 test/OpenApiEndToEndTests/QueryStrings/PaginationTests.cs create mode 100644 test/OpenApiEndToEndTests/QueryStrings/SortTests.cs create mode 100644 test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs create mode 100644 test/OpenApiEndToEndTests/QueryStrings/swagger.g.json create mode 100644 test/OpenApiTests/QueryStrings/Node.cs create mode 100644 test/OpenApiTests/QueryStrings/QueryStringFakers.cs create mode 100644 test/OpenApiTests/QueryStrings/QueryStringTests.cs create mode 100644 test/OpenApiTests/QueryStrings/QueryStringsDbContext.cs diff --git a/docs/usage/openapi-client.md b/docs/usage/openapi-client.md index 7596300fb2..d21378826c 100644 --- a/docs/usage/openapi-client.md +++ b/docs/usage/openapi-client.md @@ -32,7 +32,12 @@ The next steps describe how to generate a JSON:API client library and use our pa using var httpClient = new HttpClient(); var apiClient = new ExampleApiClient("http://localhost:14140", httpClient); - PersonCollectionResponseDocument getResponse = await apiClient.GetPersonCollectionAsync(); + PersonCollectionResponseDocument getResponse = await apiClient.GetPersonCollectionAsync(new Dictionary + { + ["filter"] = "has(assignedTodoItems)", + ["sort"] = "-lastName", + ["page[size]"] = "5" + }); foreach (PersonDataInResponse person in getResponse.Data) { @@ -88,7 +93,8 @@ The next steps describe how to generate a JSON:API client library and use our pa using (apiClient.WithPartialAttributeSerialization(patchRequest, person => person.FirstName)) { - await TranslateAsync(async () => await apiClient.PatchPersonAsync(1, patchRequest)); + // Workaround for https://github.com/RicoSuter/NSwag/issues/2499. + await TranslateAsync(async () => await apiClient.PatchPersonAsync(1, null, patchRequest)); // The sent request looks like this: // { @@ -102,20 +108,6 @@ The next steps describe how to generate a JSON:API client library and use our pa // } // } } - - static async Task TranslateAsync(Func> operation) - where TResponse : class - { - try - { - return await operation(); - } - catch (ApiException exception) when (exception.StatusCode == 204) - { - // Workaround for https://github.com/RicoSuter/NSwag/issues/2499 - return null; - } - } ``` ### Other IDEs diff --git a/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json b/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json index 797f5e7708..3ef29cfffe 100644 --- a/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json +++ b/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json @@ -10,10 +10,26 @@ "tags": [ "people" ], + "summary": "Retrieves a collection of people.", "operationId": "getPersonCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found people, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -28,17 +44,27 @@ "tags": [ "people" ], + "summary": "Retrieves a collection of people without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headPersonCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/personCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." } } }, @@ -46,19 +72,40 @@ "tags": [ "people" ], + "summary": "Creates a new person.", "operationId": "postPerson", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { + "description": "The attributes and relationships of the person to create.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/personPostRequestDocument" + "allOf": [ + { + "$ref": "#/components/schemas/personPostRequestDocument" + } + ] } } } }, "responses": { "201": { - "description": "Created", + "description": "The person was successfully created, which resulted in additional changes. The newly created person is returned.", "content": { "application/vnd.api+json": { "schema": { @@ -68,7 +115,19 @@ } }, "204": { - "description": "No Content" + "description": "The person was successfully created, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -78,21 +137,36 @@ "tags": [ "people" ], + "summary": "Retrieves an individual person by its identifier.", "operationId": "getPerson", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found person.", "content": { "application/vnd.api+json": { "schema": { @@ -100,6 +174,9 @@ } } } + }, + "404": { + "description": "The person does not exist." } } }, @@ -107,28 +184,40 @@ "tags": [ "people" ], + "summary": "Retrieves an individual person by its identifier without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headPerson", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/personPrimaryResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The person does not exist." } } }, @@ -136,30 +225,50 @@ "tags": [ "people" ], + "summary": "Updates an existing person.", "operationId": "patchPerson", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to update.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { + "description": "The attributes and relationships of the person to update. Omitted fields are left unchanged.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/personPatchRequestDocument" + "allOf": [ + { + "$ref": "#/components/schemas/personPatchRequestDocument" + } + ] } } } }, "responses": { "200": { - "description": "Success", + "description": "The person was successfully updated, which resulted in additional changes. The updated person is returned.", "content": { "application/vnd.api+json": { "schema": { @@ -169,7 +278,19 @@ } }, "204": { - "description": "No Content" + "description": "The person was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The person or a related resource does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type or identifier in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." } } }, @@ -177,11 +298,13 @@ "tags": [ "people" ], + "summary": "Deletes an existing person by its identifier.", "operationId": "deletePerson", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to delete.", "required": true, "schema": { "type": "integer", @@ -191,7 +314,10 @@ ], "responses": { "204": { - "description": "No Content" + "description": "The person was successfully deleted." + }, + "404": { + "description": "The person does not exist." } } } @@ -201,21 +327,36 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItems of an individual person's assignedTodoItems relationship.", "operationId": "getPersonAssignedTodoItems", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItems to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItems, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -223,6 +364,9 @@ } } } + }, + "404": { + "description": "The person does not exist." } } }, @@ -230,28 +374,40 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItems of an individual person's assignedTodoItems relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headPersonAssignedTodoItems", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItems to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The person does not exist." } } } @@ -261,21 +417,36 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItem identities of an individual person's assignedTodoItems relationship.", "operationId": "getPersonAssignedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItem identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItem identities, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -283,6 +454,9 @@ } } } + }, + "404": { + "description": "The person does not exist." } } }, @@ -290,28 +464,40 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItem identities of an individual person's assignedTodoItems relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headPersonAssignedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItem identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemIdentifierCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The person does not exist." } } }, @@ -319,11 +505,13 @@ "tags": [ "people" ], + "summary": "Adds existing todoItems to the assignedTodoItems relationship of an individual person.", "operationId": "postPersonAssignedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to add todoItems to.", "required": true, "schema": { "type": "integer", @@ -332,17 +520,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to add to the assignedTodoItems relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The todoItems were successfully added, which did not result in additional changes." + }, + "404": { + "description": "The person does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -350,11 +552,13 @@ "tags": [ "people" ], + "summary": "Assigns existing todoItems to the assignedTodoItems relationship of an individual person.", "operationId": "patchPersonAssignedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose assignedTodoItems relationship to assign.", "required": true, "schema": { "type": "integer", @@ -363,17 +567,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to assign to the assignedTodoItems relationship, or an empty array to clear the relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The assignedTodoItems relationship was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The person does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -381,11 +599,13 @@ "tags": [ "people" ], + "summary": "Removes existing todoItems from the assignedTodoItems relationship of an individual person.", "operationId": "deletePersonAssignedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to remove todoItems from.", "required": true, "schema": { "type": "integer", @@ -394,17 +614,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to remove from the assignedTodoItems relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The todoItems were successfully removed, which did not result in additional changes." + }, + "404": { + "description": "The person does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } } @@ -414,21 +648,36 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItems of an individual person's ownedTodoItems relationship.", "operationId": "getPersonOwnedTodoItems", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItems to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItems, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -436,6 +685,9 @@ } } } + }, + "404": { + "description": "The person does not exist." } } }, @@ -443,28 +695,40 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItems of an individual person's ownedTodoItems relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headPersonOwnedTodoItems", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItems to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The person does not exist." } } } @@ -474,21 +738,36 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItem identities of an individual person's ownedTodoItems relationship.", "operationId": "getPersonOwnedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItem identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItem identities, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -496,6 +775,9 @@ } } } + }, + "404": { + "description": "The person does not exist." } } }, @@ -503,28 +785,40 @@ "tags": [ "people" ], + "summary": "Retrieves the related todoItem identities of an individual person's ownedTodoItems relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headPersonOwnedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose related todoItem identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemIdentifierCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The person does not exist." } } }, @@ -532,11 +826,13 @@ "tags": [ "people" ], + "summary": "Adds existing todoItems to the ownedTodoItems relationship of an individual person.", "operationId": "postPersonOwnedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to add todoItems to.", "required": true, "schema": { "type": "integer", @@ -545,17 +841,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to add to the ownedTodoItems relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The todoItems were successfully added, which did not result in additional changes." + }, + "404": { + "description": "The person does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -563,11 +873,13 @@ "tags": [ "people" ], + "summary": "Assigns existing todoItems to the ownedTodoItems relationship of an individual person.", "operationId": "patchPersonOwnedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person whose ownedTodoItems relationship to assign.", "required": true, "schema": { "type": "integer", @@ -576,17 +888,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to assign to the ownedTodoItems relationship, or an empty array to clear the relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The ownedTodoItems relationship was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The person does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -594,11 +920,13 @@ "tags": [ "people" ], + "summary": "Removes existing todoItems from the ownedTodoItems relationship of an individual person.", "operationId": "deletePersonOwnedTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the person to remove todoItems from.", "required": true, "schema": { "type": "integer", @@ -607,17 +935,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to remove from the ownedTodoItems relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The todoItems were successfully removed, which did not result in additional changes." + }, + "404": { + "description": "The person does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } } @@ -627,10 +969,26 @@ "tags": [ "tags" ], + "summary": "Retrieves a collection of tags.", "operationId": "getTagCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found tags, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -645,17 +1003,27 @@ "tags": [ "tags" ], + "summary": "Retrieves a collection of tags without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTagCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tagCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." } } }, @@ -663,19 +1031,40 @@ "tags": [ "tags" ], + "summary": "Creates a new tag.", "operationId": "postTag", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { + "description": "The attributes and relationships of the tag to create.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tagPostRequestDocument" + "allOf": [ + { + "$ref": "#/components/schemas/tagPostRequestDocument" + } + ] } } } }, "responses": { "201": { - "description": "Created", + "description": "The tag was successfully created, which resulted in additional changes. The newly created tag is returned.", "content": { "application/vnd.api+json": { "schema": { @@ -685,7 +1074,19 @@ } }, "204": { - "description": "No Content" + "description": "The tag was successfully created, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -695,21 +1096,36 @@ "tags": [ "tags" ], + "summary": "Retrieves an individual tag by its identifier.", "operationId": "getTag", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found tag.", "content": { "application/vnd.api+json": { "schema": { @@ -717,6 +1133,9 @@ } } } + }, + "404": { + "description": "The tag does not exist." } } }, @@ -724,28 +1143,40 @@ "tags": [ "tags" ], + "summary": "Retrieves an individual tag by its identifier without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTag", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tagPrimaryResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The tag does not exist." } } }, @@ -753,30 +1184,50 @@ "tags": [ "tags" ], + "summary": "Updates an existing tag.", "operationId": "patchTag", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag to update.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { + "description": "The attributes and relationships of the tag to update. Omitted fields are left unchanged.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tagPatchRequestDocument" + "allOf": [ + { + "$ref": "#/components/schemas/tagPatchRequestDocument" + } + ] } } } }, "responses": { "200": { - "description": "Success", + "description": "The tag was successfully updated, which resulted in additional changes. The updated tag is returned.", "content": { "application/vnd.api+json": { "schema": { @@ -786,7 +1237,19 @@ } }, "204": { - "description": "No Content" + "description": "The tag was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The tag or a related resource does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type or identifier in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." } } }, @@ -794,11 +1257,13 @@ "tags": [ "tags" ], + "summary": "Deletes an existing tag by its identifier.", "operationId": "deleteTag", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag to delete.", "required": true, "schema": { "type": "integer", @@ -808,7 +1273,10 @@ ], "responses": { "204": { - "description": "No Content" + "description": "The tag was successfully deleted." + }, + "404": { + "description": "The tag does not exist." } } } @@ -818,21 +1286,36 @@ "tags": [ "tags" ], + "summary": "Retrieves the related todoItems of an individual tag's todoItems relationship.", "operationId": "getTagTodoItems", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag whose related todoItems to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItems, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -840,6 +1323,9 @@ } } } + }, + "404": { + "description": "The tag does not exist." } } }, @@ -847,28 +1333,40 @@ "tags": [ "tags" ], + "summary": "Retrieves the related todoItems of an individual tag's todoItems relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTagTodoItems", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag whose related todoItems to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The tag does not exist." } } } @@ -878,21 +1376,36 @@ "tags": [ "tags" ], + "summary": "Retrieves the related todoItem identities of an individual tag's todoItems relationship.", "operationId": "getTagTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag whose related todoItem identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItem identities, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -900,6 +1413,9 @@ } } } + }, + "404": { + "description": "The tag does not exist." } } }, @@ -907,28 +1423,40 @@ "tags": [ "tags" ], + "summary": "Retrieves the related todoItem identities of an individual tag's todoItems relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTagTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag whose related todoItem identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemIdentifierCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The tag does not exist." } } }, @@ -936,11 +1464,13 @@ "tags": [ "tags" ], + "summary": "Adds existing todoItems to the todoItems relationship of an individual tag.", "operationId": "postTagTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag to add todoItems to.", "required": true, "schema": { "type": "integer", @@ -949,17 +1479,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to add to the todoItems relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The todoItems were successfully added, which did not result in additional changes." + }, + "404": { + "description": "The tag does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -967,11 +1511,13 @@ "tags": [ "tags" ], + "summary": "Assigns existing todoItems to the todoItems relationship of an individual tag.", "operationId": "patchTagTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag whose todoItems relationship to assign.", "required": true, "schema": { "type": "integer", @@ -980,17 +1526,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to assign to the todoItems relationship, or an empty array to clear the relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The todoItems relationship was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The tag does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -998,11 +1558,13 @@ "tags": [ "tags" ], + "summary": "Removes existing todoItems from the todoItems relationship of an individual tag.", "operationId": "deleteTagTodoItemsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the tag to remove todoItems from.", "required": true, "schema": { "type": "integer", @@ -1011,17 +1573,31 @@ } ], "requestBody": { + "description": "The identities of the todoItems to remove from the todoItems relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The todoItems were successfully removed, which did not result in additional changes." + }, + "404": { + "description": "The tag does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } } @@ -1031,10 +1607,26 @@ "tags": [ "todoItems" ], + "summary": "Retrieves a collection of todoItems.", "operationId": "getTodoItemCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItems, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -1049,17 +1641,27 @@ "tags": [ "todoItems" ], + "summary": "Retrieves a collection of todoItems without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItemCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." } } }, @@ -1067,19 +1669,40 @@ "tags": [ "todoItems" ], + "summary": "Creates a new todoItem.", "operationId": "postTodoItem", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { + "description": "The attributes and relationships of the todoItem to create.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/todoItemPostRequestDocument" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemPostRequestDocument" + } + ] } } } }, "responses": { "201": { - "description": "Created", + "description": "The todoItem was successfully created, which resulted in additional changes. The newly created todoItem is returned.", "content": { "application/vnd.api+json": { "schema": { @@ -1089,7 +1712,19 @@ } }, "204": { - "description": "No Content" + "description": "The todoItem was successfully created, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -1099,21 +1734,36 @@ "tags": [ "todoItems" ], + "summary": "Retrieves an individual todoItem by its identifier.", "operationId": "getTodoItem", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found todoItem.", "content": { "application/vnd.api+json": { "schema": { @@ -1121,6 +1771,9 @@ } } } + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1128,28 +1781,40 @@ "tags": [ "todoItems" ], + "summary": "Retrieves an individual todoItem by its identifier without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItem", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/todoItemPrimaryResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1157,30 +1822,50 @@ "tags": [ "todoItems" ], + "summary": "Updates an existing todoItem.", "operationId": "patchTodoItem", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem to update.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { + "description": "The attributes and relationships of the todoItem to update. Omitted fields are left unchanged.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/todoItemPatchRequestDocument" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemPatchRequestDocument" + } + ] } } } }, "responses": { "200": { - "description": "Success", + "description": "The todoItem was successfully updated, which resulted in additional changes. The updated todoItem is returned.", "content": { "application/vnd.api+json": { "schema": { @@ -1190,7 +1875,19 @@ } }, "204": { - "description": "No Content" + "description": "The todoItem was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The todoItem or a related resource does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type or identifier in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." } } }, @@ -1198,11 +1895,13 @@ "tags": [ "todoItems" ], + "summary": "Deletes an existing todoItem by its identifier.", "operationId": "deleteTodoItem", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem to delete.", "required": true, "schema": { "type": "integer", @@ -1212,7 +1911,10 @@ ], "responses": { "204": { - "description": "No Content" + "description": "The todoItem was successfully deleted." + }, + "404": { + "description": "The todoItem does not exist." } } } @@ -1222,21 +1924,36 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person of an individual todoItem's assignee relationship.", "operationId": "getTodoItemAssignee", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found person, or `null` if it was not found.", "content": { "application/vnd.api+json": { "schema": { @@ -1244,6 +1961,9 @@ } } } + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1251,28 +1971,40 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person of an individual todoItem's assignee relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItemAssignee", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/nullablePersonSecondaryResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The todoItem does not exist." } } } @@ -1282,21 +2014,36 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person identity of an individual todoItem's assignee relationship.", "operationId": "getTodoItemAssigneeRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person identity to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found person identity, or `null` if it was not found.", "content": { "application/vnd.api+json": { "schema": { @@ -1304,6 +2051,9 @@ } } } + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1311,28 +2061,40 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person identity of an individual todoItem's assignee relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItemAssigneeRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person identity to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/nullablePersonIdentifierResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1340,11 +2102,13 @@ "tags": [ "todoItems" ], + "summary": "Clears or assigns an existing person to the assignee relationship of an individual todoItem.", "operationId": "patchTodoItemAssigneeRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose assignee relationship to assign or clear.", "required": true, "schema": { "type": "integer", @@ -1353,17 +2117,31 @@ } ], "requestBody": { + "description": "The identity of the person to assign to the assignee relationship, or `null` to clear the relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/nullableToOnePersonInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOnePersonInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The assignee relationship was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The todoItem does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } } @@ -1373,21 +2151,36 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person of an individual todoItem's owner relationship.", "operationId": "getTodoItemOwner", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found person, or `null` if it was not found.", "content": { "application/vnd.api+json": { "schema": { @@ -1395,6 +2188,9 @@ } } } + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1402,28 +2198,40 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person of an individual todoItem's owner relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItemOwner", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/personSecondaryResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The todoItem does not exist." } } } @@ -1433,21 +2241,36 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person identity of an individual todoItem's owner relationship.", "operationId": "getTodoItemOwnerRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person identity to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found person identity, or `null` if it was not found.", "content": { "application/vnd.api+json": { "schema": { @@ -1455,6 +2278,9 @@ } } } + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1462,28 +2288,40 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related person identity of an individual todoItem's owner relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItemOwnerRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related person identity to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/personIdentifierResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1491,11 +2329,13 @@ "tags": [ "todoItems" ], + "summary": "Assigns an existing person to the owner relationship of an individual todoItem.", "operationId": "patchTodoItemOwnerRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose owner relationship to assign.", "required": true, "schema": { "type": "integer", @@ -1504,17 +2344,31 @@ } ], "requestBody": { + "description": "The identity of the person to assign to the owner relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toOnePersonInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toOnePersonInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The owner relationship was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The todoItem does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } } @@ -1524,21 +2378,36 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related tags of an individual todoItem's tags relationship.", "operationId": "getTodoItemTags", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related tags to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found tags, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -1546,6 +2415,9 @@ } } } + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1553,28 +2425,40 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related tags of an individual todoItem's tags relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItemTags", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related tags to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tagCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The todoItem does not exist." } } } @@ -1584,21 +2468,36 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related tag identities of an individual todoItem's tags relationship.", "operationId": "getTodoItemTagsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related tag identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", + "description": "Successfully returns the found tag identities, or an empty array if none were found.", "content": { "application/vnd.api+json": { "schema": { @@ -1606,6 +2505,9 @@ } } } + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1613,28 +2515,40 @@ "tags": [ "todoItems" ], + "summary": "Retrieves the related tag identities of an individual todoItem's tags relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headTodoItemTagsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose related tag identities to retrieve.", "required": true, "schema": { "type": "integer", "format": "int64" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tagIdentifierCollectionResponseDocument" - } - } - } + "description": "The operation completed successfully." + }, + "404": { + "description": "The todoItem does not exist." } } }, @@ -1642,11 +2556,13 @@ "tags": [ "todoItems" ], + "summary": "Adds existing tags to the tags relationship of an individual todoItem.", "operationId": "postTodoItemTagsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem to add tags to.", "required": true, "schema": { "type": "integer", @@ -1655,17 +2571,31 @@ } ], "requestBody": { + "description": "The identities of the tags to add to the tags relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTagInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTagInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The tags were successfully added, which did not result in additional changes." + }, + "404": { + "description": "The todoItem does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -1673,11 +2603,13 @@ "tags": [ "todoItems" ], + "summary": "Assigns existing tags to the tags relationship of an individual todoItem.", "operationId": "patchTodoItemTagsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem whose tags relationship to assign.", "required": true, "schema": { "type": "integer", @@ -1686,17 +2618,31 @@ } ], "requestBody": { + "description": "The identities of the tags to assign to the tags relationship, or an empty array to clear the relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTagInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTagInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The tags relationship was successfully updated, which did not result in additional changes." + }, + "404": { + "description": "The todoItem does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } }, @@ -1704,11 +2650,13 @@ "tags": [ "todoItems" ], + "summary": "Removes existing tags from the tags relationship of an individual todoItem.", "operationId": "deleteTodoItemTagsRelationship", "parameters": [ { "name": "id", "in": "path", + "description": "The identifier of the todoItem to remove tags from.", "required": true, "schema": { "type": "integer", @@ -1717,17 +2665,31 @@ } ], "requestBody": { + "description": "The identities of the tags to remove from the tags relationship.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/toManyTagInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTagInRequest" + } + ] } } } }, "responses": { "204": { - "description": "No Content" + "description": "The tags were successfully removed, which did not result in additional changes." + }, + "404": { + "description": "The todoItem does not exist." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "409": { + "description": "A resource type in the request body is incompatible." } } } @@ -1780,7 +2742,6 @@ }, "linksInResourceCollectionDocument": { "required": [ - "first", "self" ], "type": "object", @@ -1793,7 +2754,6 @@ "type": "string" }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -1826,7 +2786,6 @@ }, "linksInResourceIdentifierCollectionDocument": { "required": [ - "first", "related", "self" ], @@ -1836,15 +2795,14 @@ "minLength": 1, "type": "string" }, - "describedby": { - "type": "string" - }, "related": { "minLength": 1, "type": "string" }, + "describedby": { + "type": "string" + }, "first": { - "minLength": 1, "type": "string" }, "last": { @@ -1870,12 +2828,12 @@ "minLength": 1, "type": "string" }, - "describedby": { - "type": "string" - }, "related": { "minLength": 1, "type": "string" + }, + "describedby": { + "type": "string" } }, "additionalProperties": false @@ -1893,29 +2851,6 @@ }, "additionalProperties": false }, - "nullValue": { - "not": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "object" - }, - { - "type": "array" - } - ], - "items": { } - }, - "nullable": true - }, "nullablePersonIdentifierResponseDocument": { "required": [ "data", @@ -1923,25 +2858,24 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierDocument" + } + ] + }, "data": { - "oneOf": [ + "allOf": [ { "$ref": "#/components/schemas/personIdentifier" - }, - { - "$ref": "#/components/schemas/nullValue" } - ] + ], + "nullable": true }, "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceIdentifierDocument" } }, "additionalProperties": false @@ -1953,25 +2887,24 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, "data": { - "oneOf": [ + "allOf": [ { "$ref": "#/components/schemas/personDataInResponse" - }, - { - "$ref": "#/components/schemas/nullValue" } - ] + ], + "nullable": true }, "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceDocument" } }, "additionalProperties": false @@ -1983,14 +2916,12 @@ "type": "object", "properties": { "data": { - "oneOf": [ + "allOf": [ { "$ref": "#/components/schemas/personIdentifier" - }, - { - "$ref": "#/components/schemas/nullValue" } - ] + ], + "nullable": true } }, "additionalProperties": false @@ -2001,18 +2932,20 @@ ], "type": "object", "properties": { - "data": { - "oneOf": [ - { - "$ref": "#/components/schemas/personIdentifier" - }, + "links": { + "allOf": [ { - "$ref": "#/components/schemas/nullValue" + "$ref": "#/components/schemas/linksInRelationshipObject" } ] }, - "links": { - "$ref": "#/components/schemas/linksInRelationshipObject" + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/personIdentifier" + } + ], + "nullable": true }, "meta": { "type": "object", @@ -2078,6 +3011,13 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceCollectionDocument" + } + ] + }, "data": { "type": "array", "items": { @@ -2087,12 +3027,6 @@ "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceCollectionDocument" } }, "additionalProperties": false @@ -2105,17 +3039,29 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/personResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/personResourceType" + } + ] }, "id": { "minLength": 1, "type": "string" }, "attributes": { - "$ref": "#/components/schemas/personAttributesInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/personAttributesInPatchRequest" + } + ] }, "relationships": { - "$ref": "#/components/schemas/personRelationshipsInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/personRelationshipsInPatchRequest" + } + ] } }, "additionalProperties": false @@ -2127,13 +3073,25 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/personResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/personResourceType" + } + ] }, "attributes": { - "$ref": "#/components/schemas/personAttributesInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/personAttributesInPostRequest" + } + ] }, "relationships": { - "$ref": "#/components/schemas/personRelationshipsInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/personRelationshipsInPostRequest" + } + ] } }, "additionalProperties": false @@ -2147,20 +3105,36 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/personResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/personResourceType" + } + ] }, "id": { "minLength": 1, "type": "string" }, "attributes": { - "$ref": "#/components/schemas/personAttributesInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/personAttributesInResponse" + } + ] }, "relationships": { - "$ref": "#/components/schemas/personRelationshipsInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/personRelationshipsInResponse" + } + ] }, "links": { - "$ref": "#/components/schemas/linksInResourceObject" + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceObject" + } + ] }, "meta": { "type": "object", @@ -2177,7 +3151,11 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/personResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/personResourceType" + } + ] }, "id": { "minLength": 1, @@ -2193,18 +3171,23 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierDocument" + } + ] + }, "data": { - "$ref": "#/components/schemas/personIdentifier" + "allOf": [ + { + "$ref": "#/components/schemas/personIdentifier" + } + ] }, "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceIdentifierDocument" } }, "additionalProperties": false @@ -2216,7 +3199,11 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/personDataInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/personDataInPatchRequest" + } + ] } }, "additionalProperties": false @@ -2228,7 +3215,11 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/personDataInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/personDataInPostRequest" + } + ] } }, "additionalProperties": false @@ -2240,18 +3231,23 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, "data": { - "$ref": "#/components/schemas/personDataInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/personDataInResponse" + } + ] }, "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceDocument" } }, "additionalProperties": false @@ -2260,10 +3256,18 @@ "type": "object", "properties": { "ownedTodoItems": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] }, "assignedTodoItems": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } }, "additionalProperties": false @@ -2272,10 +3276,18 @@ "type": "object", "properties": { "ownedTodoItems": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] }, "assignedTodoItems": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } }, "additionalProperties": false @@ -2284,10 +3296,18 @@ "type": "object", "properties": { "ownedTodoItems": { - "$ref": "#/components/schemas/toManyTodoItemInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInResponse" + } + ] }, "assignedTodoItems": { - "$ref": "#/components/schemas/toManyTodoItemInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInResponse" + } + ] } }, "additionalProperties": false @@ -2305,18 +3325,23 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, "data": { - "$ref": "#/components/schemas/personDataInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/personDataInResponse" + } + ] }, "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceDocument" } }, "additionalProperties": false @@ -2364,6 +3389,13 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceCollectionDocument" + } + ] + }, "data": { "type": "array", "items": { @@ -2373,12 +3405,6 @@ "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceCollectionDocument" } }, "additionalProperties": false @@ -2391,17 +3417,29 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/tagResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/tagResourceType" + } + ] }, "id": { "minLength": 1, "type": "string" }, "attributes": { - "$ref": "#/components/schemas/tagAttributesInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/tagAttributesInPatchRequest" + } + ] }, "relationships": { - "$ref": "#/components/schemas/tagRelationshipsInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/tagRelationshipsInPatchRequest" + } + ] } }, "additionalProperties": false @@ -2413,13 +3451,25 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/tagResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/tagResourceType" + } + ] }, "attributes": { - "$ref": "#/components/schemas/tagAttributesInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/tagAttributesInPostRequest" + } + ] }, "relationships": { - "$ref": "#/components/schemas/tagRelationshipsInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/tagRelationshipsInPostRequest" + } + ] } }, "additionalProperties": false @@ -2433,20 +3483,36 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/tagResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/tagResourceType" + } + ] }, "id": { "minLength": 1, "type": "string" }, "attributes": { - "$ref": "#/components/schemas/tagAttributesInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/tagAttributesInResponse" + } + ] }, "relationships": { - "$ref": "#/components/schemas/tagRelationshipsInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/tagRelationshipsInResponse" + } + ] }, "links": { - "$ref": "#/components/schemas/linksInResourceObject" + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceObject" + } + ] }, "meta": { "type": "object", @@ -2463,7 +3529,11 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/tagResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/tagResourceType" + } + ] }, "id": { "minLength": 1, @@ -2479,6 +3549,13 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument" + } + ] + }, "data": { "type": "array", "items": { @@ -2488,12 +3565,6 @@ "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument" } }, "additionalProperties": false @@ -2505,7 +3576,11 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/tagDataInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/tagDataInPatchRequest" + } + ] } }, "additionalProperties": false @@ -2517,7 +3592,11 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/tagDataInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/tagDataInPostRequest" + } + ] } }, "additionalProperties": false @@ -2529,18 +3608,23 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, "data": { - "$ref": "#/components/schemas/tagDataInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/tagDataInResponse" + } + ] }, "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceDocument" } }, "additionalProperties": false @@ -2549,7 +3633,11 @@ "type": "object", "properties": { "todoItems": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } }, "additionalProperties": false @@ -2558,7 +3646,11 @@ "type": "object", "properties": { "todoItems": { - "$ref": "#/components/schemas/toManyTodoItemInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInRequest" + } + ] } }, "additionalProperties": false @@ -2567,7 +3659,11 @@ "type": "object", "properties": { "todoItems": { - "$ref": "#/components/schemas/toManyTodoItemInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTodoItemInResponse" + } + ] } }, "additionalProperties": false @@ -2599,15 +3695,19 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInRelationshipObject" + } + ] + }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/tagIdentifier" } }, - "links": { - "$ref": "#/components/schemas/linksInRelationshipObject" - }, "meta": { "type": "object", "additionalProperties": { } @@ -2636,15 +3736,19 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInRelationshipObject" + } + ] + }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/todoItemIdentifier" } }, - "links": { - "$ref": "#/components/schemas/linksInRelationshipObject" - }, "meta": { "type": "object", "additionalProperties": { } @@ -2659,7 +3763,11 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/personIdentifier" + "allOf": [ + { + "$ref": "#/components/schemas/personIdentifier" + } + ] } }, "additionalProperties": false @@ -2670,11 +3778,19 @@ ], "type": "object", "properties": { - "data": { - "$ref": "#/components/schemas/personIdentifier" - }, "links": { - "$ref": "#/components/schemas/linksInRelationshipObject" + "allOf": [ + { + "$ref": "#/components/schemas/linksInRelationshipObject" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/personIdentifier" + } + ] }, "meta": { "type": "object", @@ -2690,7 +3806,11 @@ "type": "string" }, "priority": { - "$ref": "#/components/schemas/todoItemPriority" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemPriority" + } + ] }, "durationInHours": { "type": "integer", @@ -2711,7 +3831,11 @@ "type": "string" }, "priority": { - "$ref": "#/components/schemas/todoItemPriority" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemPriority" + } + ] }, "durationInHours": { "type": "integer", @@ -2732,7 +3856,11 @@ "type": "string" }, "priority": { - "$ref": "#/components/schemas/todoItemPriority" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemPriority" + } + ] }, "durationInHours": { "type": "integer", @@ -2758,6 +3886,13 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceCollectionDocument" + } + ] + }, "data": { "type": "array", "items": { @@ -2767,12 +3902,6 @@ "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceCollectionDocument" } }, "additionalProperties": false @@ -2785,17 +3914,29 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/todoItemResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemResourceType" + } + ] }, "id": { "minLength": 1, "type": "string" }, "attributes": { - "$ref": "#/components/schemas/todoItemAttributesInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemAttributesInPatchRequest" + } + ] }, "relationships": { - "$ref": "#/components/schemas/todoItemRelationshipsInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemRelationshipsInPatchRequest" + } + ] } }, "additionalProperties": false @@ -2807,13 +3948,25 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/todoItemResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemResourceType" + } + ] }, "attributes": { - "$ref": "#/components/schemas/todoItemAttributesInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemAttributesInPostRequest" + } + ] }, "relationships": { - "$ref": "#/components/schemas/todoItemRelationshipsInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemRelationshipsInPostRequest" + } + ] } }, "additionalProperties": false @@ -2827,20 +3980,36 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/todoItemResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemResourceType" + } + ] }, "id": { "minLength": 1, "type": "string" }, "attributes": { - "$ref": "#/components/schemas/todoItemAttributesInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemAttributesInResponse" + } + ] }, "relationships": { - "$ref": "#/components/schemas/todoItemRelationshipsInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemRelationshipsInResponse" + } + ] }, "links": { - "$ref": "#/components/schemas/linksInResourceObject" + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceObject" + } + ] }, "meta": { "type": "object", @@ -2857,7 +4026,11 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/todoItemResourceType" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemResourceType" + } + ] }, "id": { "minLength": 1, @@ -2873,6 +4046,13 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument" + } + ] + }, "data": { "type": "array", "items": { @@ -2882,12 +4062,6 @@ "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument" } }, "additionalProperties": false @@ -2899,7 +4073,11 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/todoItemDataInPatchRequest" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemDataInPatchRequest" + } + ] } }, "additionalProperties": false @@ -2911,7 +4089,11 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/todoItemDataInPostRequest" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemDataInPostRequest" + } + ] } }, "additionalProperties": false @@ -2923,18 +4105,23 @@ ], "type": "object", "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, "data": { - "$ref": "#/components/schemas/todoItemDataInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/todoItemDataInResponse" + } + ] }, "meta": { "type": "object", "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapiObject" - }, - "links": { - "$ref": "#/components/schemas/linksInResourceDocument" } }, "additionalProperties": false @@ -2951,13 +4138,25 @@ "type": "object", "properties": { "owner": { - "$ref": "#/components/schemas/toOnePersonInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toOnePersonInRequest" + } + ] }, "assignee": { - "$ref": "#/components/schemas/nullableToOnePersonInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOnePersonInRequest" + } + ] }, "tags": { - "$ref": "#/components/schemas/toManyTagInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTagInRequest" + } + ] } }, "additionalProperties": false @@ -2969,13 +4168,25 @@ "type": "object", "properties": { "owner": { - "$ref": "#/components/schemas/toOnePersonInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toOnePersonInRequest" + } + ] }, "assignee": { - "$ref": "#/components/schemas/nullableToOnePersonInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOnePersonInRequest" + } + ] }, "tags": { - "$ref": "#/components/schemas/toManyTagInRequest" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTagInRequest" + } + ] } }, "additionalProperties": false @@ -2987,13 +4198,25 @@ "type": "object", "properties": { "owner": { - "$ref": "#/components/schemas/toOnePersonInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/toOnePersonInResponse" + } + ] }, "assignee": { - "$ref": "#/components/schemas/nullableToOnePersonInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOnePersonInResponse" + } + ] }, "tags": { - "$ref": "#/components/schemas/toManyTagInResponse" + "allOf": [ + { + "$ref": "#/components/schemas/toManyTagInResponse" + } + ] } }, "additionalProperties": false diff --git a/src/Examples/JsonApiDotNetCoreExampleClient/Program.cs b/src/Examples/JsonApiDotNetCoreExampleClient/Program.cs index 1ef318fa65..6424fd45e5 100644 --- a/src/Examples/JsonApiDotNetCoreExampleClient/Program.cs +++ b/src/Examples/JsonApiDotNetCoreExampleClient/Program.cs @@ -3,7 +3,12 @@ using var httpClient = new HttpClient(); var apiClient = new ExampleApiClient("http://localhost:14140", httpClient); -PersonCollectionResponseDocument getResponse = await apiClient.GetPersonCollectionAsync(); +PersonCollectionResponseDocument getResponse = await apiClient.GetPersonCollectionAsync(new Dictionary +{ + ["filter"] = "has(assignedTodoItems)", + ["sort"] = "-lastName", + ["page[size]"] = "5" +}); foreach (PersonDataInResponse person in getResponse.Data) { @@ -25,7 +30,8 @@ // This line results in sending "firstName: null" instead of omitting it. using (apiClient.WithPartialAttributeSerialization(patchRequest, person => person.FirstName)) { - await TranslateAsync(async () => await apiClient.PatchPersonAsync(1, patchRequest)); + // Workaround for https://github.com/RicoSuter/NSwag/issues/2499. + await TranslateAsync(async () => await apiClient.PatchPersonAsync(1, null, patchRequest)); } Console.WriteLine("Press any key to close."); diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiOperationDocumentationFilter.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiOperationDocumentationFilter.cs index a5abe45263..6421b56c07 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiOperationDocumentationFilter.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiOperationDocumentationFilter.cs @@ -7,6 +7,7 @@ using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Resources.Annotations; using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; @@ -29,12 +30,20 @@ internal sealed class JsonApiOperationDocumentationFilter : IOperationFilter "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched."; private const string TextCompletedSuccessfully = "The operation completed successfully."; - private const string TextRequestBodyMissingOrMalformed = "The request body is missing or malformed."; + private const string TextQueryStringBad = "The query string is invalid."; + private const string TextRequestBodyBad = "The request body is missing or malformed."; + private const string TextQueryStringOrRequestBodyBad = "The query string is invalid or the request body is missing or malformed."; private const string TextRequestBodyIncompatibleType = "A resource type in the request body is incompatible."; private const string TextRequestBodyIncompatibleIdOrType = "A resource type or identifier in the request body is incompatible."; private const string TextRequestBodyValidationFailed = "Validation of the request body failed."; private const string TextRequestBodyClientId = "Client-generated IDs cannot be used at this endpoint."; + private const string TextQueryStringParameters = + "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/" + + "[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/" + + "[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/" + + "[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters."; + private readonly IJsonApiOptions _options; private readonly IControllerResourceMapping _controllerResourceMapping; private readonly ResourceFieldValidationMetadataProvider _resourceFieldValidationMetadataProvider; @@ -156,6 +165,9 @@ private static void ApplyGetPrimary(OpenApiOperation operation, ResourceType res SetResponseDescription(operation.Responses, HttpStatusCode.OK, $"Successfully returns the found {resourceType}, or an empty array if none were found."); } + + AddQueryStringParameters(operation); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringBad); } else if (operation.Parameters.Count == 1) { @@ -174,6 +186,8 @@ private static void ApplyGetPrimary(OpenApiOperation operation, ResourceType res } SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularName} to retrieve."); + AddQueryStringParameters(operation); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringBad); SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularName} does not exist."); } } @@ -183,6 +197,7 @@ private void ApplyPostResource(OpenApiOperation operation, ResourceType resource string singularName = resourceType.PublicName.Singularize(); SetOperationSummary(operation, $"Creates a new {singularName}."); + AddQueryStringParameters(operation); SetRequestBodyDescription(operation.RequestBody, $"The attributes and relationships of the {singularName} to create."); SetResponseDescription(operation.Responses, HttpStatusCode.Created, @@ -191,9 +206,7 @@ private void ApplyPostResource(OpenApiOperation operation, ResourceType resource SetResponseDescription(operation.Responses, HttpStatusCode.NoContent, $"The {singularName} was successfully created, which did not result in additional changes."); - SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyMissingOrMalformed); - SetResponseDescription(operation.Responses, HttpStatusCode.Conflict, TextRequestBodyIncompatibleType); - SetResponseDescription(operation.Responses, HttpStatusCode.UnprocessableEntity, TextRequestBodyValidationFailed); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringOrRequestBodyBad); ClientIdGenerationMode clientIdGeneration = resourceType.ClientIdGeneration ?? _options.ClientIdGeneration; @@ -201,6 +214,9 @@ private void ApplyPostResource(OpenApiOperation operation, ResourceType resource { SetResponseDescription(operation.Responses, HttpStatusCode.Forbidden, TextRequestBodyClientId); } + + SetResponseDescription(operation.Responses, HttpStatusCode.Conflict, TextRequestBodyIncompatibleType); + SetResponseDescription(operation.Responses, HttpStatusCode.UnprocessableEntity, TextRequestBodyValidationFailed); } private void ApplyPatchResource(OpenApiOperation operation, ResourceType resourceType) @@ -209,6 +225,7 @@ private void ApplyPatchResource(OpenApiOperation operation, ResourceType resourc SetOperationSummary(operation, $"Updates an existing {singularName}."); SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularName} to update."); + AddQueryStringParameters(operation); SetRequestBodyDescription(operation.RequestBody, $"The attributes and relationships of the {singularName} to update. Omitted fields are left unchanged."); @@ -219,8 +236,8 @@ private void ApplyPatchResource(OpenApiOperation operation, ResourceType resourc SetResponseDescription(operation.Responses, HttpStatusCode.NoContent, $"The {singularName} was successfully updated, which did not result in additional changes."); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringOrRequestBodyBad); SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularName} or a related resource does not exist."); - SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyMissingOrMalformed); SetResponseDescription(operation.Responses, HttpStatusCode.Conflict, TextRequestBodyIncompatibleIdOrType); SetResponseDescription(operation.Responses, HttpStatusCode.UnprocessableEntity, TextRequestBodyValidationFailed); } @@ -261,6 +278,8 @@ relationship is HasOneAttribute } SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} whose related {rightName} to retrieve."); + AddQueryStringParameters(operation); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringBad); SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularLeftName} does not exist."); } @@ -292,6 +311,8 @@ relationship is HasOneAttribute } SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} whose related {singularRightName} {ident} to retrieve."); + AddQueryStringParameters(operation); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringBad); SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularLeftName} does not exist."); } @@ -307,8 +328,8 @@ private void ApplyPostRelationship(OpenApiOperation operation, RelationshipAttri SetResponseDescription(operation.Responses, HttpStatusCode.NoContent, $"The {rightName} were successfully added, which did not result in additional changes."); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyBad); SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularLeftName} does not exist."); - SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyMissingOrMalformed); SetResponseDescription(operation.Responses, HttpStatusCode.Conflict, TextRequestBodyIncompatibleType); } @@ -340,8 +361,8 @@ relationship is HasOneAttribute SetResponseDescription(operation.Responses, HttpStatusCode.NoContent, $"The {relationship} relationship was successfully updated, which did not result in additional changes."); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyBad); SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularLeftName} does not exist."); - SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyMissingOrMalformed); SetResponseDescription(operation.Responses, HttpStatusCode.Conflict, TextRequestBodyIncompatibleType); } @@ -357,8 +378,8 @@ private void ApplyDeleteRelationship(OpenApiOperation operation, RelationshipAtt SetResponseDescription(operation.Responses, HttpStatusCode.NoContent, $"The {rightName} were successfully removed, which did not result in additional changes."); + SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyBad); SetResponseDescription(operation.Responses, HttpStatusCode.NotFound, $"The {singularLeftName} does not exist."); - SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextRequestBodyMissingOrMalformed); SetResponseDescription(operation.Responses, HttpStatusCode.Conflict, TextRequestBodyIncompatibleType); } @@ -405,4 +426,35 @@ private static void SetResponseDescription(OpenApiResponses responses, HttpStatu response.Description = XmlCommentsTextHelper.Humanize(description); } + + private static void AddQueryStringParameters(OpenApiOperation operation) + { + // The JSON:API query string parameters (include, filter, sort, page[size], page[number], fields[]) are too dynamic to represent in OpenAPI. + // - The parameter names for fields[] require exploding to all resource types, because outcome of possible resource types depends on + // the relationship chains in include, which are provided at invocation time. + // - The parameter names for filter/sort take a relationship path, which could be infinite. For example: ?filter[node.parent.parent.parent...]=... + + // The next best thing is to expose the query string parameters as unstructured and optional. + // - This makes SwaggerUI ask for JSON, which is a bit odd, but it works. For example: {"sort":"-id"} produces: ?sort=-id + // - This makes NSwag produce a C# client with method signature: GetAsync(IDictionary? query) + // when combined with /GenerateNullableReferenceTypes:true in the project file. + + operation.Parameters.Add(new OpenApiParameter + { + In = ParameterLocation.Query, + Name = "query", + Schema = new OpenApiSchema + { + Type = "object", + AdditionalProperties = new OpenApiSchema + { + Type = "string", + Nullable = true + }, + // Prevent SwaggerUI from producing sample, which fails when used because unknown query string parameters are blocked by default. + Example = new OpenApiNull() + }, + Description = TextQueryStringParameters + }); + } } diff --git a/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs b/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs index a5cb4cc434..6086d85c5b 100644 --- a/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs +++ b/test/OpenApiClientTests/LegacyClient/PartialAttributeSerializationLifetimeTests.cs @@ -31,13 +31,13 @@ public async Task Disposed_registration_does_not_affect_request() using (apiClient.WithPartialAttributeSerialization(requestDocument, airplane => airplane.AirtimeInHours)) { - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, null, requestDocument)); } wrapper.ChangeResponse(HttpStatusCode.NoContent, null); // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, null, requestDocument)); // Assert wrapper.RequestBody.Should().BeJson(@"{ @@ -76,14 +76,14 @@ public async Task Registration_can_be_used_for_multiple_requests() using (apiClient.WithPartialAttributeSerialization(requestDocument, airplane => airplane.AirtimeInHours)) { - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, null, requestDocument)); wrapper.ChangeResponse(HttpStatusCode.NoContent, null); requestDocument.Data.Attributes.AirtimeInHours = null; // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, null, requestDocument)); } // Assert @@ -138,7 +138,7 @@ public async Task Request_is_unaffected_by_registration_for_different_document_o } // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId2, requestDocument2)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId2, null, requestDocument2)); } // Assert @@ -181,7 +181,7 @@ public async Task Attribute_values_can_be_changed_after_registration() requestDocument.Data.Attributes.IsInMaintenance = false; // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, null, requestDocument)); } // Assert @@ -231,7 +231,7 @@ public async Task Registration_is_unaffected_by_successive_registration_for_docu airplane => airplane.AirtimeInHours)) { // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId1, requestDocument1)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId1, null, requestDocument1)); } } @@ -269,7 +269,7 @@ public async Task Registration_is_unaffected_by_preceding_disposed_registration_ using (apiClient.WithPartialAttributeSerialization(requestDocument1, airplane => airplane.AirtimeInHours)) { - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId1, requestDocument1)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId1, null, requestDocument1)); } const string airplaneId2 = "DJy1u"; @@ -293,7 +293,7 @@ public async Task Registration_is_unaffected_by_preceding_disposed_registration_ airplane => airplane.SerialNumber)) { // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId2, requestDocument2)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId2, null, requestDocument2)); } // Assert @@ -331,7 +331,7 @@ public async Task Registration_is_unaffected_by_preceding_disposed_registration_ using (apiClient.WithPartialAttributeSerialization(requestDocument1, airplane => airplane.AirtimeInHours)) { - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PostAirplaneAsync(requestDocument1)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PostAirplaneAsync(null, requestDocument1)); } const string airplaneId = "DJy1u"; @@ -355,7 +355,7 @@ public async Task Registration_is_unaffected_by_preceding_disposed_registration_ airplane => airplane.SerialNumber)) { // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, requestDocument2)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, null, requestDocument2)); } // Assert @@ -409,7 +409,7 @@ public async Task Registration_is_unaffected_by_preceding_registration_for_diffe airplane => airplane.IsInMaintenance, airplane => airplane.AirtimeInHours)) { // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId2, requestDocument2)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId2, null, requestDocument2)); } } diff --git a/test/OpenApiClientTests/LegacyClient/RequestTests.cs b/test/OpenApiClientTests/LegacyClient/RequestTests.cs index 908cde4742..20d91c44a6 100644 --- a/test/OpenApiClientTests/LegacyClient/RequestTests.cs +++ b/test/OpenApiClientTests/LegacyClient/RequestTests.cs @@ -23,7 +23,7 @@ public async Task Getting_resource_collection_produces_expected_request() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightCollectionAsync()); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightCollectionAsync(null)); // Assert wrapper.Request.ShouldNotBeNull(); @@ -43,7 +43,7 @@ public async Task Getting_resource_produces_expected_request() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightAsync(flightId)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightAsync(flightId, null)); // Assert wrapper.Request.ShouldNotBeNull(); @@ -88,7 +88,7 @@ public async Task Partial_posting_resource_with_selected_relationships_produces_ }; // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PostFlightAsync(requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PostFlightAsync(null, requestDocument)); // Assert wrapper.Request.ShouldNotBeNull(); @@ -157,7 +157,7 @@ public async Task Partial_posting_resource_produces_expected_request() airplane => airplane.SerialNumber)) { // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PostAirplaneAsync(requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PostAirplaneAsync(null, requestDocument)); } // Assert @@ -208,7 +208,7 @@ public async Task Partial_patching_resource_produces_expected_request() airplane => airplane.SerialNumber, airplane => airplane.LastServicedAt, airplane => airplane.IsInMaintenance, airplane => airplane.AirtimeInHours)) { // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, requestDocument)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.PatchAirplaneAsync(airplaneId, null, requestDocument)); } // Assert @@ -263,7 +263,7 @@ public async Task Getting_secondary_resource_produces_expected_request() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightPurserAsync(flightId)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightPurserAsync(flightId, null)); // Assert wrapper.Request.ShouldNotBeNull(); @@ -283,7 +283,7 @@ public async Task Getting_secondary_resources_produces_expected_request() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightCabinCrewMembersAsync(flightId)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightCabinCrewMembersAsync(flightId, null)); // Assert wrapper.Request.ShouldNotBeNull(); @@ -303,7 +303,7 @@ public async Task Getting_ToOne_relationship_produces_expected_request() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightPurserRelationshipAsync(flightId)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightPurserRelationshipAsync(flightId, null)); // Assert wrapper.Request.ShouldNotBeNull(); @@ -360,7 +360,7 @@ public async Task Getting_ToMany_relationship_produces_expected_request() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightCabinCrewMembersRelationshipAsync(flightId)); + _ = await ApiResponse.TranslateAsync(async () => await apiClient.GetFlightCabinCrewMembersRelationshipAsync(flightId, null)); // Assert wrapper.Request.ShouldNotBeNull(); diff --git a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs index 73669ba5fc..c837d8bb50 100644 --- a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs +++ b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs @@ -97,7 +97,7 @@ public async Task Getting_resource_collection_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightCollectionResponseDocument document = await apiClient.GetFlightCollectionAsync(); + FlightCollectionResponseDocument document = await apiClient.GetFlightCollectionAsync(null); // Assert document.Jsonapi.Should().BeNull(); @@ -177,7 +177,7 @@ public async Task Getting_resource_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightPrimaryResponseDocument document = await apiClient.GetFlightAsync(flightId); + FlightPrimaryResponseDocument document = await apiClient.GetFlightAsync(flightId, null); // Assert document.Jsonapi.Should().BeNull(); @@ -213,7 +213,7 @@ public async Task Getting_unknown_resource_translates_error_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.GetFlightAsync(flightId); + Func> action = async () => await apiClient.GetFlightAsync(flightId, null); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -277,7 +277,7 @@ public async Task Posting_resource_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightPrimaryResponseDocument document = await apiClient.PostFlightAsync(new FlightPostRequestDocument + FlightPrimaryResponseDocument document = await apiClient.PostFlightAsync(null, new FlightPostRequestDocument { Data = new FlightDataInPostRequest { @@ -329,7 +329,7 @@ public async Task Patching_resource_with_side_effects_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightPrimaryResponseDocument document = await apiClient.PatchFlightAsync(flightId, new FlightPatchRequestDocument + FlightPrimaryResponseDocument document = await apiClient.PatchFlightAsync(flightId, null, new FlightPatchRequestDocument { Data = new FlightDataInPatchRequest { @@ -353,7 +353,7 @@ public async Task Patching_resource_without_side_effects_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightPrimaryResponseDocument? document = await ApiResponse.TranslateAsync(async () => await apiClient.PatchFlightAsync(flightId, + FlightPrimaryResponseDocument? document = await ApiResponse.TranslateAsync(async () => await apiClient.PatchFlightAsync(flightId, null, new FlightPatchRequestDocument { Data = new FlightDataInPatchRequest @@ -431,7 +431,7 @@ public async Task Getting_secondary_resource_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightAttendantSecondaryResponseDocument document = await apiClient.GetFlightPurserAsync(flightId); + FlightAttendantSecondaryResponseDocument document = await apiClient.GetFlightPurserAsync(flightId, null); // Assert document.Data.Should().NotBeNull(); @@ -461,7 +461,7 @@ public async Task Getting_nullable_secondary_resource_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - NullableFlightAttendantSecondaryResponseDocument document = await apiClient.GetFlightBackupPurserAsync(flightId); + NullableFlightAttendantSecondaryResponseDocument document = await apiClient.GetFlightBackupPurserAsync(flightId, null); // Assert document.Data.Should().BeNull(); @@ -485,7 +485,7 @@ public async Task Getting_secondary_resources_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightAttendantCollectionResponseDocument document = await apiClient.GetFlightCabinCrewMembersAsync(flightId); + FlightAttendantCollectionResponseDocument document = await apiClient.GetFlightCabinCrewMembersAsync(flightId, null); // Assert document.Data.Should().BeEmpty(); @@ -509,7 +509,7 @@ public async Task Getting_nullable_ToOne_relationship_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - NullableFlightAttendantIdentifierResponseDocument document = await apiClient.GetFlightBackupPurserRelationshipAsync(flightId); + NullableFlightAttendantIdentifierResponseDocument document = await apiClient.GetFlightBackupPurserRelationshipAsync(flightId, null); // Assert document.Data.Should().BeNull(); @@ -537,7 +537,7 @@ public async Task Getting_ToOne_relationship_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightAttendantIdentifierResponseDocument document = await apiClient.GetFlightPurserRelationshipAsync(flightId); + FlightAttendantIdentifierResponseDocument document = await apiClient.GetFlightPurserRelationshipAsync(flightId, null); // Assert document.Data.Should().NotBeNull(); @@ -591,7 +591,7 @@ public async Task Getting_ToMany_relationship_translates_response() IOpenApiClient apiClient = new OpenApiClient(wrapper.HttpClient); // Act - FlightAttendantIdentifierCollectionResponseDocument document = await apiClient.GetFlightCabinCrewMembersRelationshipAsync(flightId); + FlightAttendantIdentifierCollectionResponseDocument document = await apiClient.GetFlightCabinCrewMembersRelationshipAsync(flightId, null); // Assert document.Data.Should().HaveCount(2); diff --git a/test/OpenApiClientTests/LegacyClient/swagger.g.json b/test/OpenApiClientTests/LegacyClient/swagger.g.json index 6042d7be81..8480de70d4 100644 --- a/test/OpenApiClientTests/LegacyClient/swagger.g.json +++ b/test/OpenApiClientTests/LegacyClient/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of airplanes.", "operationId": "get-airplane-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found airplanes, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of airplanes without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "head-airplane-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new airplane.", "operationId": "post-airplane", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the airplane to create.", "content": { @@ -73,16 +124,16 @@ "description": "The airplane was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -103,6 +154,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -116,6 +180,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -137,12 +204,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -163,6 +246,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -193,12 +289,12 @@ "204": { "description": "The airplane was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The airplane or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -250,6 +346,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -263,6 +372,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -284,12 +396,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -312,6 +440,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -325,6 +466,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -346,12 +490,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -392,12 +552,12 @@ "204": { "description": "The flights were successfully added, which did not result in additional changes." }, - "404": { - "description": "The airplane does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The airplane does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -438,12 +598,12 @@ "204": { "description": "The flights relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The airplane does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The airplane does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -484,12 +644,12 @@ "204": { "description": "The flights were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The airplane does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The airplane does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -503,6 +663,21 @@ ], "summary": "Retrieves a collection of flight-attendants.", "operationId": "get-flight-attendant-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found flight-attendants, or an empty array if none were found.", @@ -513,6 +688,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -523,9 +701,27 @@ "summary": "Retrieves a collection of flight-attendants without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "head-flight-attendant-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -535,6 +731,21 @@ ], "summary": "Creates a new flight-attendant.", "operationId": "post-flight-attendant", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the flight-attendant to create.", "content": { @@ -564,16 +775,16 @@ "description": "The flight-attendant was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -594,6 +805,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -607,6 +831,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -628,12 +855,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -654,6 +897,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -684,12 +940,12 @@ "204": { "description": "The flight-attendant was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The flight-attendant or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -741,6 +997,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -754,6 +1023,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -775,12 +1047,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -803,6 +1091,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -816,6 +1117,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -837,12 +1141,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -883,12 +1203,12 @@ "204": { "description": "The flights were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -929,12 +1249,12 @@ "204": { "description": "The purser-on-flights relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -975,12 +1295,12 @@ "204": { "description": "The flights were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1003,6 +1323,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1016,6 +1349,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1037,12 +1373,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1065,6 +1417,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1078,6 +1443,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1099,12 +1467,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1145,12 +1529,12 @@ "204": { "description": "The flights were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1191,12 +1575,12 @@ "204": { "description": "The scheduled-for-flights relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1237,12 +1621,12 @@ "204": { "description": "The flights were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1256,6 +1640,21 @@ ], "summary": "Retrieves a collection of flights.", "operationId": "get-flight-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found flights, or an empty array if none were found.", @@ -1266,6 +1665,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1276,9 +1678,27 @@ "summary": "Retrieves a collection of flights without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "head-flight-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1288,6 +1708,21 @@ ], "summary": "Creates a new flight.", "operationId": "post-flight", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the flight to create.", "content": { @@ -1317,16 +1752,16 @@ "description": "The flight was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -1347,6 +1782,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1360,6 +1808,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1381,12 +1832,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1407,6 +1874,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -1437,12 +1917,12 @@ "204": { "description": "The flight was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The flight or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -1494,6 +1974,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1507,6 +2000,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1528,12 +2024,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1556,6 +2068,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1569,6 +2094,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1590,12 +2118,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1636,12 +2180,12 @@ "204": { "description": "The backup-purser relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1664,6 +2208,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1677,6 +2234,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1698,12 +2258,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1726,6 +2302,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1739,6 +2328,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1760,12 +2352,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1806,12 +2414,12 @@ "204": { "description": "The flight-attendants were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1852,12 +2460,12 @@ "204": { "description": "The cabin-crew-members relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1898,12 +2506,12 @@ "204": { "description": "The flight-attendants were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1926,6 +2534,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1939,6 +2560,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1960,12 +2584,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1988,6 +2628,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -2001,6 +2654,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2022,12 +2678,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2068,12 +2740,12 @@ "204": { "description": "The passengers were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2114,12 +2786,12 @@ "204": { "description": "The passengers relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2160,12 +2832,12 @@ "204": { "description": "The passengers were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2188,6 +2860,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -2201,6 +2886,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2222,12 +2910,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2250,6 +2954,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -2263,6 +2980,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2284,12 +3004,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2330,12 +3066,12 @@ "204": { "description": "The purser relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json index 7c935d1d30..33c24ef622 100644 --- a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of supermarkets.", "operationId": "getSupermarketCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found supermarkets, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of supermarkets without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headSupermarketCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new supermarket.", "operationId": "postSupermarket", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the supermarket to create.", "content": { @@ -73,16 +124,16 @@ "description": "The supermarket was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -104,6 +155,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -117,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -139,12 +206,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -166,6 +249,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -196,12 +292,12 @@ "204": { "description": "The supermarket was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The supermarket or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -255,6 +351,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -268,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -290,12 +402,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -319,6 +447,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -332,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -354,12 +498,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -401,12 +561,12 @@ "204": { "description": "The backupStoreManager relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -430,6 +590,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -443,6 +616,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -465,12 +641,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -494,6 +686,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -507,6 +712,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -529,12 +737,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -576,12 +800,12 @@ "204": { "description": "The staffMembers were successfully added, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -623,12 +847,12 @@ "204": { "description": "The cashiers relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -670,12 +894,12 @@ "204": { "description": "The staffMembers were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -699,6 +923,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -712,6 +949,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -734,12 +974,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -763,6 +1019,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -776,6 +1045,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -798,12 +1070,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -845,12 +1133,12 @@ "204": { "description": "The storeManager relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json index a182e7f9aa..859ab008c9 100644 --- a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of supermarkets.", "operationId": "get-supermarket-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found supermarkets, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of supermarkets without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "head-supermarket-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new supermarket.", "operationId": "post-supermarket", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the supermarket to create.", "content": { @@ -73,16 +124,16 @@ "description": "The supermarket was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -104,6 +155,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -117,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -139,12 +206,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -166,6 +249,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -196,12 +292,12 @@ "204": { "description": "The supermarket was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The supermarket or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -255,6 +351,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -268,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -290,12 +402,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -319,6 +447,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -332,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -354,12 +498,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -401,12 +561,12 @@ "204": { "description": "The backup-store-manager relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -430,6 +590,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -443,6 +616,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -465,12 +641,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -494,6 +686,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -507,6 +712,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -529,12 +737,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -576,12 +800,12 @@ "204": { "description": "The staff-members were successfully added, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -623,12 +847,12 @@ "204": { "description": "The cashiers relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -670,12 +894,12 @@ "204": { "description": "The staff-members were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -699,6 +923,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -712,6 +949,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -734,12 +974,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -763,6 +1019,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -776,6 +1045,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -798,12 +1070,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The supermarket does not exist." } @@ -845,12 +1133,12 @@ "204": { "description": "The store-manager relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json index d10af305bc..bf35e16505 100644 --- a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of Supermarkets.", "operationId": "GetSupermarketCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found Supermarkets, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of Supermarkets without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "HeadSupermarketCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new Supermarket.", "operationId": "PostSupermarket", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the Supermarket to create.", "content": { @@ -73,16 +124,16 @@ "description": "The Supermarket was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -104,6 +155,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -117,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -139,12 +206,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -166,6 +249,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -196,12 +292,12 @@ "204": { "description": "The Supermarket was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The Supermarket or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -255,6 +351,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -268,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -290,12 +402,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -319,6 +447,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -332,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -354,12 +498,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -401,12 +561,12 @@ "204": { "description": "The BackupStoreManager relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The Supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The Supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -430,6 +590,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -443,6 +616,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -465,12 +641,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -494,6 +686,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -507,6 +712,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -529,12 +737,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -576,12 +800,12 @@ "204": { "description": "The StaffMembers were successfully added, which did not result in additional changes." }, - "404": { - "description": "The Supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The Supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -623,12 +847,12 @@ "204": { "description": "The Cashiers relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The Supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The Supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -670,12 +894,12 @@ "204": { "description": "The StaffMembers were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The Supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The Supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -699,6 +923,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -712,6 +949,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -734,12 +974,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -763,6 +1019,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -776,6 +1045,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -798,12 +1070,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The Supermarket does not exist." } @@ -845,12 +1133,12 @@ "204": { "description": "The StoreManager relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The Supermarket does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The Supermarket does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs index 3d965583f4..f2eada42fa 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/CreateResourceTests.cs @@ -51,7 +51,7 @@ public async Task Can_set_attribute_to_default_value(string attributePropertyNam using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument, includeAttributeSelector); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -92,7 +92,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -133,7 +133,7 @@ public async Task Cannot_omit_attribute(string attributePropertyName, string jso using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -169,7 +169,7 @@ public async Task Can_clear_relationship(string relationshipPropertyName, string var apiClient = new NrtOffMsvOffClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -207,7 +207,7 @@ public async Task Cannot_clear_relationship(string relationshipPropertyName, str var apiClient = new NrtOffMsvOffClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -243,7 +243,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOffMsvOffClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs index b5dd28dd87..bad0c97842 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/UpdateResourceTests.cs @@ -37,7 +37,7 @@ public async Task Cannot_omit_Id() var apiClient = new NrtOffMsvOffClient(wrapper.HttpClient); // Act - Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, requestDocument); + Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -79,7 +79,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -120,7 +120,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOffMsvOffClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json index 7479ee14e4..c8bf47ffa5 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of resources.", "operationId": "getResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found resources, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of resources without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new resource.", "operationId": "postResource", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the resource to create.", "content": { @@ -73,16 +124,16 @@ "description": "The resource was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -104,6 +155,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -117,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -139,12 +206,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -166,6 +249,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -196,12 +292,12 @@ "204": { "description": "The resource was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The resource or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -255,6 +351,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -268,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -290,12 +402,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -319,6 +447,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -332,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -354,12 +498,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -401,12 +561,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -448,12 +608,12 @@ "204": { "description": "The requiredToMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -495,12 +655,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -524,6 +684,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -537,6 +710,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -559,12 +735,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -588,6 +780,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -601,6 +806,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -623,12 +831,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -670,12 +894,12 @@ "204": { "description": "The requiredToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -699,6 +923,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -712,6 +949,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -734,12 +974,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -763,6 +1019,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -776,6 +1045,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -798,12 +1070,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -845,12 +1133,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -892,12 +1180,12 @@ "204": { "description": "The toMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -939,12 +1227,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -968,6 +1256,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -981,6 +1282,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1003,12 +1307,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1032,6 +1352,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1045,6 +1378,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1067,12 +1403,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1114,12 +1466,12 @@ "204": { "description": "The toOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs index 674a5f75ca..e4565eb40c 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/CreateResourceTests.cs @@ -50,7 +50,7 @@ public async Task Can_set_attribute_to_default_value(string attributePropertyNam using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument, includeAttributeSelector); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -92,7 +92,7 @@ public async Task Cannot_set_attribute_to_default_value(string attributeProperty using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument, includeAttributeSelector); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -131,7 +131,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -171,7 +171,7 @@ public async Task Cannot_omit_attribute(string attributePropertyName, string jso using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -206,7 +206,7 @@ public async Task Can_clear_relationship(string relationshipPropertyName, string var apiClient = new NrtOffMsvOnClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -245,7 +245,7 @@ public async Task Cannot_clear_relationship(string relationshipPropertyName, str var apiClient = new NrtOffMsvOnClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -282,7 +282,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOffMsvOnClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -319,7 +319,7 @@ public async Task Cannot_omit_relationship(string relationshipPropertyName, stri var apiClient = new NrtOffMsvOnClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs index 770ca101f3..5b430f0c07 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/UpdateResourceTests.cs @@ -37,7 +37,7 @@ public async Task Cannot_omit_Id() var apiClient = new NrtOffMsvOnClient(wrapper.HttpClient); // Act - Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, requestDocument); + Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -79,7 +79,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -120,7 +120,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOffMsvOnClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json index 960af45209..6375f83fca 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of resources.", "operationId": "getResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found resources, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of resources without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new resource.", "operationId": "postResource", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the resource to create.", "content": { @@ -73,16 +124,16 @@ "description": "The resource was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -104,6 +155,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -117,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -139,12 +206,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -166,6 +249,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -196,12 +292,12 @@ "204": { "description": "The resource was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The resource or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -255,6 +351,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -268,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -290,12 +402,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -319,6 +447,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -332,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -354,12 +498,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -401,12 +561,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -448,12 +608,12 @@ "204": { "description": "The requiredToMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -495,12 +655,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -524,6 +684,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -537,6 +710,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -559,12 +735,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -588,6 +780,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -601,6 +806,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -623,12 +831,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -670,12 +894,12 @@ "204": { "description": "The requiredToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -699,6 +923,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -712,6 +949,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -734,12 +974,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -763,6 +1019,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -776,6 +1045,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -798,12 +1070,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -845,12 +1133,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -892,12 +1180,12 @@ "204": { "description": "The toMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -939,12 +1227,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -968,6 +1256,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -981,6 +1282,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1003,12 +1307,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1032,6 +1352,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1045,6 +1378,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1067,12 +1403,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1114,12 +1466,12 @@ "204": { "description": "The toOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs index 9bc4d70a76..1ca0771467 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/CreateResourceTests.cs @@ -53,7 +53,7 @@ public async Task Can_set_attribute_to_default_value(string attributePropertyNam using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument, includeAttributeSelector); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -98,7 +98,7 @@ public async Task Cannot_set_attribute_to_default_value(string attributeProperty using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument, includeAttributeSelector); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -140,7 +140,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -184,7 +184,7 @@ public async Task Cannot_omit_attribute(string attributePropertyName, string jso using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -222,7 +222,7 @@ public async Task Can_clear_relationship(string relationshipPropertyName, string var apiClient = new NrtOnMsvOffClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -264,7 +264,7 @@ public async Task Cannot_clear_relationship(string relationshipPropertyName, str var apiClient = new NrtOnMsvOffClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -303,7 +303,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOnMsvOffClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -342,7 +342,7 @@ public async Task Cannot_omit_relationship(string relationshipPropertyName, stri var apiClient = new NrtOnMsvOffClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs index 9e2f8a1164..96ed010cd4 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/UpdateResourceTests.cs @@ -39,7 +39,7 @@ public async Task Cannot_omit_Id() var apiClient = new NrtOnMsvOffClient(wrapper.HttpClient); // Act - Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, requestDocument); + Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -85,7 +85,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -130,7 +130,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOnMsvOffClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json index 8e93abc1a9..ea99c5e179 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of resources.", "operationId": "getResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found resources, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of resources without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new resource.", "operationId": "postResource", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the resource to create.", "content": { @@ -73,16 +124,16 @@ "description": "The resource was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -104,6 +155,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -117,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -139,12 +206,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -166,6 +249,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -196,12 +292,12 @@ "204": { "description": "The resource was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The resource or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -255,6 +351,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -268,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -290,12 +402,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -319,6 +447,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -332,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -354,12 +498,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -401,12 +561,12 @@ "204": { "description": "The nonNullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -430,6 +590,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -443,6 +616,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -465,12 +641,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -494,6 +686,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -507,6 +712,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -529,12 +737,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -576,12 +800,12 @@ "204": { "description": "The nullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -605,6 +829,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -618,6 +855,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -640,12 +880,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -669,6 +925,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -682,6 +951,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -704,12 +976,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -751,12 +1039,12 @@ "204": { "description": "The requiredNonNullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -780,6 +1068,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -793,6 +1094,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -815,12 +1119,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -844,6 +1164,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -857,6 +1190,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -879,12 +1215,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -926,12 +1278,12 @@ "204": { "description": "The requiredNullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -955,6 +1307,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -968,6 +1333,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -990,12 +1358,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1019,6 +1403,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1032,6 +1429,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1054,12 +1454,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1101,12 +1517,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1148,12 +1564,12 @@ "204": { "description": "The requiredToMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1195,12 +1611,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1224,6 +1640,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1237,6 +1666,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1259,12 +1691,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1288,6 +1736,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1301,6 +1762,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1323,12 +1787,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1370,12 +1850,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1417,12 +1897,12 @@ "204": { "description": "The toMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1464,12 +1944,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs index cf62bf4f10..a9bab857af 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/CreateResourceTests.cs @@ -52,7 +52,7 @@ public async Task Can_set_attribute_to_default_value(string attributePropertyNam using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument, includeAttributeSelector); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -98,7 +98,7 @@ public async Task Cannot_set_attribute_to_default_value(string attributeProperty using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument, includeAttributeSelector); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -139,7 +139,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -183,7 +183,7 @@ public async Task Cannot_omit_attribute(string attributePropertyName, string jso using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -220,7 +220,7 @@ public async Task Can_clear_relationship(string relationshipPropertyName, string var apiClient = new NrtOnMsvOnClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -263,7 +263,7 @@ public async Task Cannot_clear_relationship(string relationshipPropertyName, str var apiClient = new NrtOnMsvOnClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -302,7 +302,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOnMsvOnClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PostResourceAsync(null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -343,7 +343,7 @@ public async Task Cannot_omit_relationship(string relationshipPropertyName, stri var apiClient = new NrtOnMsvOnClient(wrapper.HttpClient); // Act - Func> action = async () => await apiClient.PostResourceAsync(requestDocument); + Func> action = async () => await apiClient.PostResourceAsync(null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs index f0cc06f8e4..3fd8e55d06 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/UpdateResourceTests.cs @@ -39,7 +39,7 @@ public async Task Cannot_omit_Id() var apiClient = new NrtOnMsvOnClient(wrapper.HttpClient); // Act - Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, requestDocument); + Func action = async () => await apiClient.PatchResourceAsync(Unknown.TypedId.Int32, null, requestDocument); // Assert ExceptionAssertions assertion = await action.Should().ThrowExactlyAsync(); @@ -85,7 +85,7 @@ public async Task Can_omit_attribute(string attributePropertyName, string jsonPr using IDisposable _ = apiClient.WithPartialAttributeSerialization(requestDocument); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); @@ -130,7 +130,7 @@ public async Task Can_omit_relationship(string relationshipPropertyName, string var apiClient = new NrtOnMsvOnClient(wrapper.HttpClient); // Act - await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), requestDocument)); + await ApiResponse.TranslateAsync(async () => await apiClient.PatchResourceAsync(int.Parse(requestDocument.Data.Id), null, requestDocument)); // Assert JsonElement document = wrapper.GetRequestBodyAsJson(); diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json index 09942e918c..90f43f0c3c 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of resources.", "operationId": "getResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found resources, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of resources without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "headResourceCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new resource.", "operationId": "postResource", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the resource to create.", "content": { @@ -73,16 +124,16 @@ "description": "The resource was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -104,6 +155,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -117,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -139,12 +206,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -166,6 +249,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -196,12 +292,12 @@ "204": { "description": "The resource was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The resource or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -255,6 +351,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -268,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -290,12 +402,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -319,6 +447,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -332,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -354,12 +498,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -401,12 +561,12 @@ "204": { "description": "The nonNullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -430,6 +590,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -443,6 +616,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -465,12 +641,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -494,6 +686,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -507,6 +712,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -529,12 +737,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -576,12 +800,12 @@ "204": { "description": "The nullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -605,6 +829,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -618,6 +855,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -640,12 +880,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -669,6 +925,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -682,6 +951,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -704,12 +976,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -751,12 +1039,12 @@ "204": { "description": "The requiredNonNullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -780,6 +1068,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -793,6 +1094,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -815,12 +1119,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -844,6 +1164,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -857,6 +1190,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -879,12 +1215,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -926,12 +1278,12 @@ "204": { "description": "The requiredNullableToOne relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -955,6 +1307,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -968,6 +1333,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -990,12 +1358,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1019,6 +1403,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1032,6 +1429,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1054,12 +1454,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1101,12 +1517,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1148,12 +1564,12 @@ "204": { "description": "The requiredToMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1195,12 +1611,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1224,6 +1640,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1237,6 +1666,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1259,12 +1691,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1288,6 +1736,19 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1301,6 +1762,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1323,12 +1787,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The resource does not exist." } @@ -1370,12 +1850,12 @@ "204": { "description": "The empties were successfully added, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1417,12 +1897,12 @@ "204": { "description": "The toMany relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1464,12 +1944,12 @@ "204": { "description": "The empties were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The resource does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The resource does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiEndToEndTests/OpenApiEndToEndTests.csproj b/test/OpenApiEndToEndTests/OpenApiEndToEndTests.csproj new file mode 100644 index 0000000000..fce4f3d735 --- /dev/null +++ b/test/OpenApiEndToEndTests/OpenApiEndToEndTests.csproj @@ -0,0 +1,31 @@ + + + $(TargetFrameworkName) + + + + + + + + + + + + + + + + + + + + + OpenApiEndToEndTests.QueryStrings.GeneratedCode + QueryStringsClient + QueryStringsClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions /GenerateNullableReferenceTypes:true + + + diff --git a/test/OpenApiEndToEndTests/QueryStrings/FilterTests.cs b/test/OpenApiEndToEndTests/QueryStrings/FilterTests.cs new file mode 100644 index 0000000000..f4ea0e477b --- /dev/null +++ b/test/OpenApiEndToEndTests/QueryStrings/FilterTests.cs @@ -0,0 +1,153 @@ +using System.Net; +using FluentAssertions; +using JsonApiDotNetCore.OpenApi.Client.Exceptions; +using OpenApiEndToEndTests.QueryStrings.GeneratedCode; +using OpenApiTests; +using OpenApiTests.QueryStrings; +using TestBuildingBlocks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenApiEndToEndTests.QueryStrings; + +public sealed class FilterTests : IClassFixture, QueryStringsDbContext>> +{ + private readonly IntegrationTestContext, QueryStringsDbContext> _testContext; + private readonly ITestOutputHelper _testOutputHelper; + private readonly QueryStringFakers _fakers = new(); + + public FilterTests(IntegrationTestContext, QueryStringsDbContext> testContext, ITestOutputHelper testOutputHelper) + { + _testContext = testContext; + _testOutputHelper = testOutputHelper; + + testContext.UseController(); + } + + [Fact] + public async Task Can_filter_in_primary_resources() + { + // Arrange + List nodes = _fakers.Node.Generate(2); + nodes[0].Name = "John No Quote"; + nodes[1].Name = "Brian O'Quote"; + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.AddRange(nodes); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["filter"] = "equals(name,'Brian O''Quote')" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeCollectionAsync(queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(nodes[1].StringId); + response.Data.ElementAt(0).Attributes.Name.Should().Be(nodes[1].Name); + response.Data.ElementAt(0).Attributes.Comment.Should().Be(nodes[1].Comment); + response.Meta.ShouldNotBeNull(); + response.Meta.ShouldContainKey("total").With(total => total.Should().Be(1)); + } + + [Fact] + public async Task Can_filter_in_secondary_resources() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Children = _fakers.Node.Generate(2).ToHashSet(); + node.Children.ElementAt(0).Comment = "Discount: $10"; + node.Children.ElementAt(1).Comment = "Discount: 5%"; + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["filter"] = "and(startsWith(comment,'Discount:'),contains(comment,'%'))" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeChildrenAsync(node.Id, queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(node.Children.ElementAt(1).StringId); + response.Data.ElementAt(0).Attributes.Name.Should().Be(node.Children.ElementAt(1).Name); + response.Data.ElementAt(0).Attributes.Comment.Should().Be(node.Children.ElementAt(1).Comment); + response.Meta.ShouldNotBeNull(); + response.Meta.ShouldContainKey("total").With(total => total.Should().Be(1)); + } + + [Fact] + public async Task Can_filter_at_ToMany_relationship_endpoint() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Children = _fakers.Node.Generate(2).ToHashSet(); + node.Children.ElementAt(0).Children = _fakers.Node.Generate(1).ToHashSet(); + node.Children.ElementAt(1).Children = _fakers.Node.Generate(2).ToHashSet(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["filter"] = "greaterThan(count(children),'1')" + }; + + // Act + NodeIdentifierCollectionResponseDocument response = await apiClient.GetNodeChildrenRelationshipAsync(node.Id, queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(node.Children.ElementAt(1).StringId); + response.Meta.ShouldNotBeNull(); + response.Meta.ShouldContainKey("total").With(total => total.Should().Be(1)); + } + + [Fact] + public async Task Cannot_use_empty_filter() + { + // Arrange + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["filter"] = null + }; + + // Act + Func action = async () => _ = await apiClient.GetNodeAsync(1, queryString); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().StartWith("The query string is invalid."); + exception.Message.Should().Contain("Missing value for 'filter' query string parameter."); + } +} diff --git a/test/OpenApiEndToEndTests/QueryStrings/GeneratedCode/QueryStringsClient.cs b/test/OpenApiEndToEndTests/QueryStrings/GeneratedCode/QueryStringsClient.cs new file mode 100644 index 0000000000..e0bd59a9a7 --- /dev/null +++ b/test/OpenApiEndToEndTests/QueryStrings/GeneratedCode/QueryStringsClient.cs @@ -0,0 +1,62 @@ +using JsonApiDotNetCore.OpenApi.Client; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using TestBuildingBlocks; +using Xunit.Abstractions; + +// ReSharper disable UnusedParameterInPartialMethod + +namespace OpenApiEndToEndTests.QueryStrings.GeneratedCode; + +internal partial class QueryStringsClient : JsonApiClient +{ + private readonly ILogger? _logger; + + public QueryStringsClient(HttpClient httpClient, ITestOutputHelper testOutputHelper) + : this(httpClient, CreateLogger(testOutputHelper)) + { + } + + private QueryStringsClient(HttpClient httpClient, ILogger logger) + : this(httpClient) + { + _logger = logger; + } + + private static ILogger CreateLogger(ITestOutputHelper testOutputHelper) + { + var loggerFactory = new LoggerFactory(new[] + { + new XUnitLoggerProvider(testOutputHelper, LogOutputFields.Message) + }); + + return loggerFactory.CreateLogger(); + } + + partial void UpdateJsonSerializerSettings(JsonSerializerSettings settings) + { + SetSerializerSettingsForJsonApi(settings); + + settings.Formatting = Formatting.Indented; + } + + partial void PrepareRequest(HttpClient client, HttpRequestMessage request, string url) + { + if (_logger != null && _logger.IsEnabled(LogLevel.Debug)) + { + string? requestBody = request.Content?.ReadAsStringAsync().GetAwaiter().GetResult(); + _logger.LogDebug(requestBody != null ? $"--> {request}{Environment.NewLine}{Environment.NewLine}{requestBody}" : $"--> {request}"); + } + } + + partial void ProcessResponse(HttpClient client, HttpResponseMessage response) + { + if (_logger != null && _logger.IsEnabled(LogLevel.Debug)) + { + string responseBody = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + + _logger.LogDebug( + !string.IsNullOrEmpty(responseBody) ? $"<-- {response}{Environment.NewLine}{Environment.NewLine}{responseBody}" : $"<-- {response}"); + } + } +} diff --git a/test/OpenApiEndToEndTests/QueryStrings/PaginationTests.cs b/test/OpenApiEndToEndTests/QueryStrings/PaginationTests.cs new file mode 100644 index 0000000000..43d2208e7b --- /dev/null +++ b/test/OpenApiEndToEndTests/QueryStrings/PaginationTests.cs @@ -0,0 +1,169 @@ +using System.Net; +using FluentAssertions; +using JsonApiDotNetCore.OpenApi.Client.Exceptions; +using OpenApiEndToEndTests.QueryStrings.GeneratedCode; +using OpenApiTests; +using OpenApiTests.QueryStrings; +using TestBuildingBlocks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenApiEndToEndTests.QueryStrings; + +public sealed class PaginationTests : IClassFixture, QueryStringsDbContext>> +{ + private readonly IntegrationTestContext, QueryStringsDbContext> _testContext; + private readonly ITestOutputHelper _testOutputHelper; + private readonly QueryStringFakers _fakers = new(); + + public PaginationTests(IntegrationTestContext, QueryStringsDbContext> testContext, ITestOutputHelper testOutputHelper) + { + _testContext = testContext; + _testOutputHelper = testOutputHelper; + + testContext.UseController(); + } + + [Fact] + public async Task Can_paginate_in_primary_resources() + { + // Arrange + List nodes = _fakers.Node.Generate(3); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.AddRange(nodes); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["page[size]"] = "1", + ["page[number]"] = "2" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeCollectionAsync(queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(nodes[1].StringId); + response.Meta.ShouldNotBeNull(); + response.Meta.ShouldContainKey("total").With(total => total.Should().Be(3)); + } + + [Fact] + public async Task Can_paginate_in_secondary_resources() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Children = _fakers.Node.Generate(3).ToHashSet(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["page[size]"] = "2", + ["page[number]"] = "1" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeChildrenAsync(node.Id, queryString); + + // Assert + response.Data.Should().HaveCount(2); + response.Data.ElementAt(0).Id.Should().Be(node.Children.ElementAt(0).StringId); + response.Data.ElementAt(1).Id.Should().Be(node.Children.ElementAt(1).StringId); + response.Meta.ShouldNotBeNull(); + response.Meta.ShouldContainKey("total").With(total => total.Should().Be(3)); + } + + [Fact] + public async Task Can_paginate_at_ToMany_relationship_endpoint() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Children = _fakers.Node.Generate(3).ToHashSet(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["page[size]"] = "2", + ["page[number]"] = "2" + }; + + // Act + NodeIdentifierCollectionResponseDocument response = await apiClient.GetNodeChildrenRelationshipAsync(node.Id, queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(node.Children.ElementAt(2).StringId); + response.Meta.ShouldNotBeNull(); + response.Meta.ShouldContainKey("total").With(total => total.Should().Be(3)); + } + + [Fact] + public async Task Cannot_use_empty_page_size() + { + // Arrange + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["page[size]"] = null + }; + + // Act + Func action = async () => _ = await apiClient.GetNodeAsync(1, queryString); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().StartWith("The query string is invalid."); + exception.Message.Should().Contain("Missing value for 'page[size]' query string parameter."); + } + + [Fact] + public async Task Cannot_use_empty_page_number() + { + // Arrange + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["page[number]"] = null + }; + + // Act + Func action = async () => _ = await apiClient.GetNodeAsync(1, queryString); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().StartWith("The query string is invalid."); + exception.Message.Should().Contain("Missing value for 'page[number]' query string parameter."); + } +} diff --git a/test/OpenApiEndToEndTests/QueryStrings/SortTests.cs b/test/OpenApiEndToEndTests/QueryStrings/SortTests.cs new file mode 100644 index 0000000000..57380a7c33 --- /dev/null +++ b/test/OpenApiEndToEndTests/QueryStrings/SortTests.cs @@ -0,0 +1,146 @@ +using System.Net; +using FluentAssertions; +using JsonApiDotNetCore.OpenApi.Client.Exceptions; +using OpenApiEndToEndTests.QueryStrings.GeneratedCode; +using OpenApiTests; +using OpenApiTests.QueryStrings; +using TestBuildingBlocks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenApiEndToEndTests.QueryStrings; + +public sealed class SortTests : IClassFixture, QueryStringsDbContext>> +{ + private readonly IntegrationTestContext, QueryStringsDbContext> _testContext; + private readonly ITestOutputHelper _testOutputHelper; + private readonly QueryStringFakers _fakers = new(); + + public SortTests(IntegrationTestContext, QueryStringsDbContext> testContext, ITestOutputHelper testOutputHelper) + { + _testContext = testContext; + _testOutputHelper = testOutputHelper; + + testContext.UseController(); + } + + [Fact] + public async Task Can_sort_in_primary_resources() + { + // Arrange + List nodes = _fakers.Node.Generate(2); + nodes[0].Name = "A"; + nodes[1].Name = "B"; + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.AddRange(nodes); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["sort"] = "-name" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeCollectionAsync(queryString); + + // Assert + response.Data.Should().HaveCount(2); + response.Data.ElementAt(0).Id.Should().Be(nodes[1].StringId); + response.Data.ElementAt(1).Id.Should().Be(nodes[0].StringId); + } + + [Fact] + public async Task Can_sort_in_secondary_resources() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Children = _fakers.Node.Generate(2).ToHashSet(); + node.Children.ElementAt(0).Name = "B"; + node.Children.ElementAt(1).Name = "A"; + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["sort"] = "name" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeChildrenAsync(node.Id, queryString); + + // Assert + response.Data.Should().HaveCount(2); + response.Data.ElementAt(0).Id.Should().Be(node.Children.ElementAt(1).StringId); + response.Data.ElementAt(1).Id.Should().Be(node.Children.ElementAt(0).StringId); + } + + [Fact] + public async Task Can_sort_at_ToMany_relationship_endpoint() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Children = _fakers.Node.Generate(2).ToHashSet(); + node.Children.ElementAt(0).Children = _fakers.Node.Generate(1).ToHashSet(); + node.Children.ElementAt(1).Children = _fakers.Node.Generate(2).ToHashSet(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["sort"] = "count(children)" + }; + + // Act + NodeIdentifierCollectionResponseDocument response = await apiClient.GetNodeChildrenRelationshipAsync(node.Id, queryString); + + // Assert + response.Data.Should().HaveCount(2); + response.Data.ElementAt(0).Id.Should().Be(node.Children.ElementAt(0).StringId); + response.Data.ElementAt(1).Id.Should().Be(node.Children.ElementAt(1).StringId); + } + + [Fact] + public async Task Cannot_use_empty_sort() + { + // Arrange + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["sort"] = null + }; + + // Act + Func action = async () => _ = await apiClient.GetNodeAsync(1, queryString); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().StartWith("The query string is invalid."); + exception.Message.Should().Contain("Missing value for 'sort' query string parameter."); + } +} diff --git a/test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs b/test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs new file mode 100644 index 0000000000..091ce758af --- /dev/null +++ b/test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs @@ -0,0 +1,185 @@ +using FluentAssertions; +using OpenApiEndToEndTests.QueryStrings.GeneratedCode; +using OpenApiTests; +using OpenApiTests.QueryStrings; +using TestBuildingBlocks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenApiEndToEndTests.QueryStrings; + +public sealed class SparseFieldSetTests : IClassFixture, QueryStringsDbContext>> +{ + private readonly IntegrationTestContext, QueryStringsDbContext> _testContext; + private readonly ITestOutputHelper _testOutputHelper; + private readonly QueryStringFakers _fakers = new(); + + public SparseFieldSetTests(IntegrationTestContext, QueryStringsDbContext> testContext, + ITestOutputHelper testOutputHelper) + { + _testContext = testContext; + _testOutputHelper = testOutputHelper; + + testContext.UseController(); + } + + [Fact] + public async Task Can_select_attribute_in_primary_resources() + { + // Arrange + Node node = _fakers.Node.Generate(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["fields[nodes]"] = "name" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeCollectionAsync(queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(node.StringId); + response.Data.ElementAt(0).Attributes.Name.Should().Be(node.Name); + response.Data.ElementAt(0).Attributes.Comment.Should().BeNull(); + response.Data.ElementAt(0).Relationships.Should().BeNull(); + } + + [Fact] + public async Task Can_select_fields_in_primary_resource() + { + // Arrange + Node node = _fakers.Node.Generate(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["fields[nodes]"] = "comment,parent" + }; + + // Act + NodePrimaryResponseDocument response = await apiClient.GetNodeAsync(node.Id, queryString); + + // Assert + response.Data.Id.Should().Be(node.StringId); + response.Data.Attributes.Name.Should().BeNull(); + response.Data.Attributes.Comment.Should().Be(node.Comment); + response.Data.Relationships.Parent.Should().NotBeNull(); + response.Data.Relationships.Children.Should().BeNull(); + } + + [Fact] + public async Task Can_select_fields_in_secondary_resources() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Children = _fakers.Node.Generate(1).ToHashSet(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["fields[nodes]"] = "comment,children" + }; + + // Act + NodeCollectionResponseDocument response = await apiClient.GetNodeChildrenAsync(node.Id, queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(node.Children.ElementAt(0).StringId); + response.Data.ElementAt(0).Attributes.Name.Should().BeNull(); + response.Data.ElementAt(0).Attributes.Comment.Should().Be(node.Children.ElementAt(0).Comment); + response.Data.ElementAt(0).Relationships.Parent.Should().BeNull(); + response.Data.ElementAt(0).Relationships.Children.Should().NotBeNull(); + } + + [Fact] + public async Task Can_select_fields_in_secondary_resource() + { + // Arrange + Node node = _fakers.Node.Generate(); + node.Parent = _fakers.Node.Generate(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["fields[nodes]"] = "comment,children" + }; + + // Act + NullableNodeSecondaryResponseDocument response = await apiClient.GetNodeParentAsync(node.Id, queryString); + + // Assert + response.Data.ShouldNotBeNull(); + response.Data.Id.Should().Be(node.Parent.StringId); + response.Data.Attributes.Name.Should().BeNull(); + response.Data.Attributes.Comment.Should().Be(node.Parent.Comment); + response.Data.Relationships.Parent.Should().BeNull(); + response.Data.Relationships.Children.Should().NotBeNull(); + } + + [Fact] + public async Task Can_select_empty_fieldset() + { + // Arrange + Node node = _fakers.Node.Generate(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.Nodes.Add(node); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateClient(); + var apiClient = new QueryStringsClient(httpClient, _testOutputHelper); + + var queryString = new Dictionary + { + ["fields[nodes]"] = null + }; + + // Act + NodePrimaryResponseDocument response = await apiClient.GetNodeAsync(node.Id, queryString); + + // Assert + response.Data.Id.Should().Be(node.StringId); + response.Data.Attributes.Should().BeNull(); + } + + // TODO: Add tests for other query string parameters. +} diff --git a/test/OpenApiEndToEndTests/QueryStrings/swagger.g.json b/test/OpenApiEndToEndTests/QueryStrings/swagger.g.json new file mode 100644 index 0000000000..bf26054048 --- /dev/null +++ b/test/OpenApiEndToEndTests/QueryStrings/swagger.g.json @@ -0,0 +1,1567 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenApiTests", + "version": "1.0" + }, + "paths": { + "/nodes": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves a collection of nodes.", + "operationId": "getNodeCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found nodes, or an empty array if none were found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodeCollectionResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves a collection of nodes without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + } + } + }, + "post": { + "tags": [ + "nodes" + ], + "summary": "Creates a new node.", + "operationId": "postNode", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "requestBody": { + "description": "The attributes and relationships of the node to create.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/nodePostRequestDocument" + } + ] + } + } + } + }, + "responses": { + "201": { + "description": "The node was successfully created, which resulted in additional changes. The newly created node is returned.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodePrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "The node was successfully created, which did not result in additional changes." + }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." + }, + "409": { + "description": "A resource type in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." + } + } + } + }, + "/nodes/{id}": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves an individual node by its identifier.", + "operationId": "getNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodePrimaryResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves an individual node by its identifier without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "patch": { + "tags": [ + "nodes" + ], + "summary": "Updates an existing node.", + "operationId": "patchNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to update.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "requestBody": { + "description": "The attributes and relationships of the node to update. Omitted fields are left unchanged.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/nodePatchRequestDocument" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "The node was successfully updated, which resulted in additional changes. The updated node is returned.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodePrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "The node was successfully updated, which did not result in additional changes." + }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, + "404": { + "description": "The node or a related resource does not exist." + }, + "409": { + "description": "A resource type or identifier in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." + } + } + }, + "delete": { + "tags": [ + "nodes" + ], + "summary": "Deletes an existing node by its identifier.", + "operationId": "deleteNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to delete.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "The node was successfully deleted." + }, + "404": { + "description": "The node does not exist." + } + } + } + }, + "/nodes/{id}/children": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related nodes of an individual node's children relationship.", + "operationId": "getNodeChildren", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related nodes to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found nodes, or an empty array if none were found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodeCollectionResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related nodes of an individual node's children relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeChildren", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related nodes to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + } + }, + "/nodes/{id}/relationships/children": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identities of an individual node's children relationship.", + "operationId": "getNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identities to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node identities, or an empty array if none were found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodeIdentifierCollectionResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identities of an individual node's children relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identities to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "post": { + "tags": [ + "nodes" + ], + "summary": "Adds existing nodes to the children relationship of an individual node.", + "operationId": "postNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to add nodes to.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identities of the nodes to add to the children relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The nodes were successfully added, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + }, + "patch": { + "tags": [ + "nodes" + ], + "summary": "Assigns existing nodes to the children relationship of an individual node.", + "operationId": "patchNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose children relationship to assign.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identities of the nodes to assign to the children relationship, or an empty array to clear the relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The children relationship was successfully updated, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + }, + "delete": { + "tags": [ + "nodes" + ], + "summary": "Removes existing nodes from the children relationship of an individual node.", + "operationId": "deleteNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to remove nodes from.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identities of the nodes to remove from the children relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The nodes were successfully removed, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + } + }, + "/nodes/{id}/parent": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node of an individual node's parent relationship.", + "operationId": "getNodeParent", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node, or `null` if it was not found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableNodeSecondaryResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node of an individual node's parent relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeParent", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + } + }, + "/nodes/{id}/relationships/parent": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identity of an individual node's parent relationship.", + "operationId": "getNodeParentRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identity to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node identity, or `null` if it was not found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableNodeIdentifierResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identity of an individual node's parent relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeParentRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identity to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "patch": { + "tags": [ + "nodes" + ], + "summary": "Clears or assigns an existing node to the parent relationship of an individual node.", + "operationId": "patchNodeParentRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose parent relationship to assign or clear.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identity of the node to assign to the parent relationship, or `null` to clear the relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The parent relationship was successfully updated, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + } + } + }, + "components": { + "schemas": { + "jsonapiObject": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "ext": { + "type": "array", + "items": { + "type": "string" + } + }, + "profile": { + "type": "array", + "items": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "linksInRelationshipObject": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "related": { + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceCollectionDocument": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceDocument": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceIdentifierCollectionDocument": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "related": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceIdentifierDocument": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "related": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceObject": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false + }, + "nodeAttributesInPatchRequest": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "comment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "nodeAttributesInPostRequest": { + "required": [ + "name" + ], + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "comment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "nodeAttributesInResponse": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "comment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "nodeCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceCollectionDocument" + } + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeDataInResponse" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodeDataInPatchRequest": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "id": { + "minLength": 1, + "type": "string" + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeAttributesInPatchRequest" + } + ] + }, + "relationships": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeRelationshipsInPatchRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeDataInPostRequest": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeAttributesInPostRequest" + } + ] + }, + "relationships": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeRelationshipsInPostRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeDataInResponse": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "id": { + "minLength": 1, + "type": "string" + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeAttributesInResponse" + } + ] + }, + "relationships": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeRelationshipsInResponse" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceObject" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodeIdentifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "id": { + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false + }, + "nodeIdentifierCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument" + } + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeIdentifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodePatchRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInPatchRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodePostRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInPostRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodePrimaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInResponse" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodeRelationshipsInPatchRequest": { + "type": "object", + "properties": { + "parent": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInRequest" + } + ] + }, + "children": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeRelationshipsInPostRequest": { + "type": "object", + "properties": { + "parent": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInRequest" + } + ] + }, + "children": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeRelationshipsInResponse": { + "type": "object", + "properties": { + "parent": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInResponse" + } + ] + }, + "children": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInResponse" + } + ] + } + }, + "additionalProperties": false + }, + "nodeResourceType": { + "enum": [ + "nodes" + ], + "type": "string" + }, + "nullableNodeIdentifierResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierDocument" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeIdentifier" + } + ], + "nullable": true + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nullableNodeSecondaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInResponse" + } + ], + "nullable": true + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nullableToOneNodeInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeIdentifier" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "nullableToOneNodeInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInRelationshipObject" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeIdentifier" + } + ], + "nullable": true + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "toManyNodeInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeIdentifier" + } + } + }, + "additionalProperties": false + }, + "toManyNodeInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInRelationshipObject" + } + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeIdentifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/OpenApiTests/DocComments/DocCommentsStartup.cs b/test/OpenApiTests/DocComments/DocCommentsStartup.cs index 6049d701b1..d8c220e1a9 100644 --- a/test/OpenApiTests/DocComments/DocCommentsStartup.cs +++ b/test/OpenApiTests/DocComments/DocCommentsStartup.cs @@ -13,8 +13,9 @@ public sealed class DocCommentsStartup : OpenApiStartup { protected override void SetJsonApiOptions(JsonApiOptions options) { - options.ClientIdGeneration = ClientIdGenerationMode.Allowed; base.SetJsonApiOptions(options); + + options.ClientIdGeneration = ClientIdGenerationMode.Allowed; } protected override void SetupSwaggerGenAction(SwaggerGenOptions options) diff --git a/test/OpenApiTests/DocComments/DocCommentsTests.cs b/test/OpenApiTests/DocComments/DocCommentsTests.cs index 6d7962e47a..ae9788a0df 100644 --- a/test/OpenApiTests/DocComments/DocCommentsTests.cs +++ b/test/OpenApiTests/DocComments/DocCommentsTests.cs @@ -8,6 +8,9 @@ namespace OpenApiTests.DocComments; public sealed class DocCommentsTests : IClassFixture, DocCommentsDbContext>> { + private const string TextQueryString = + "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters."; + private readonly OpenApiTestContext, DocCommentsDbContext> _testContext; public DocCommentsTests(OpenApiTestContext, DocCommentsDbContext> testContext) @@ -59,10 +62,18 @@ public async Task Endpoints_are_documented() { getElement.Should().HaveProperty("summary", "Retrieves a collection of skyscrapers."); + getElement.Should().ContainPath("parameters").With(parametersElement => + { + parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "query"); + parametersElement.Should().HaveProperty("[0].description", TextQueryString); + }); + getElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(1); + responseElement.EnumerateObject().ShouldHaveCount(2); responseElement.Should().HaveProperty("200.description", "Successfully returns the found skyscrapers, or an empty array if none were found."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); }); }); @@ -71,10 +82,18 @@ public async Task Endpoints_are_documented() headElement.Should().HaveProperty("summary", "Retrieves a collection of skyscrapers without returning them."); headElement.Should().HaveProperty("description", "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched."); + headElement.Should().ContainPath("parameters").With(parametersElement => + { + parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "query"); + parametersElement.Should().HaveProperty("[0].description", TextQueryString); + }); + headElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(1); + responseElement.EnumerateObject().ShouldHaveCount(2); responseElement.Should().HaveProperty("200.description", "The operation completed successfully."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); }); }); @@ -82,12 +101,19 @@ public async Task Endpoints_are_documented() { postElement.Should().HaveProperty("summary", "Creates a new skyscraper."); + postElement.Should().ContainPath("parameters").With(parametersElement => + { + parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "query"); + parametersElement.Should().HaveProperty("[0].description", TextQueryString); + }); + postElement.Should().ContainPath("responses").With(responseElement => { responseElement.EnumerateObject().ShouldHaveCount(5); responseElement.Should().HaveProperty("201.description", "The skyscraper was successfully created, which resulted in additional changes. The newly created skyscraper is returned."); responseElement.Should().HaveProperty("204.description", "The skyscraper was successfully created, which did not result in additional changes."); - responseElement.Should().HaveProperty("400.description", "The request body is missing or malformed."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid or the request body is missing or malformed."); responseElement.Should().HaveProperty("409.description", "A resource type in the request body is incompatible."); responseElement.Should().HaveProperty("422.description", "Validation of the request body failed."); }); @@ -102,14 +128,18 @@ public async Task Endpoints_are_documented() getElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); getElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "Successfully returns the found skyscraper."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -121,14 +151,18 @@ public async Task Endpoints_are_documented() headElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); headElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "The operation completed successfully."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -139,8 +173,11 @@ public async Task Endpoints_are_documented() patchElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper to update."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); patchElement.Should().HaveProperty("requestBody.description", "The attributes and relationships of the skyscraper to update. Omitted fields are left unchanged."); @@ -151,7 +188,7 @@ public async Task Endpoints_are_documented() responseElement.Should().HaveProperty("200.description", "The skyscraper was successfully updated, which resulted in additional changes. The updated skyscraper is returned."); responseElement.Should().HaveProperty("204.description", "The skyscraper was successfully updated, which did not result in additional changes."); responseElement.Should().HaveProperty("404.description", "The skyscraper or a related resource does not exist."); - responseElement.Should().HaveProperty("400.description", "The request body is missing or malformed."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid or the request body is missing or malformed."); responseElement.Should().HaveProperty("409.description", "A resource type or identifier in the request body is incompatible."); responseElement.Should().HaveProperty("422.description", "Validation of the request body failed."); }); @@ -164,6 +201,7 @@ public async Task Endpoints_are_documented() patchElement.Should().ContainPath("parameters").With(parametersElement => { parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper to delete."); }); @@ -184,14 +222,18 @@ public async Task Endpoints_are_documented() getElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related elevator to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); getElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "Successfully returns the found elevator, or `null` if it was not found."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -203,14 +245,18 @@ public async Task Endpoints_are_documented() headElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related elevator to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); headElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "The operation completed successfully."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -224,14 +270,18 @@ public async Task Endpoints_are_documented() getElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related elevator identity to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); getElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "Successfully returns the found elevator identity, or `null` if it was not found."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -243,14 +293,18 @@ public async Task Endpoints_are_documented() headElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related elevator identity to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); headElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "The operation completed successfully."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -262,6 +316,7 @@ public async Task Endpoints_are_documented() patchElement.Should().ContainPath("parameters").With(parametersElement => { parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose elevator relationship to assign or clear."); }); @@ -286,14 +341,18 @@ public async Task Endpoints_are_documented() getElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related spaces to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); getElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "Successfully returns the found spaces, or an empty array if none were found."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -305,14 +364,18 @@ public async Task Endpoints_are_documented() headElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related spaces to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); headElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "The operation completed successfully."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -326,14 +389,18 @@ public async Task Endpoints_are_documented() getElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related space identities to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); getElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "Successfully returns the found space identities, or an empty array if none were found."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -345,14 +412,18 @@ public async Task Endpoints_are_documented() headElement.Should().ContainPath("parameters").With(parametersElement => { - parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.EnumerateArray().ShouldHaveCount(2); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose related space identities to retrieve."); + parametersElement.Should().HaveProperty("[1].in", "query"); + parametersElement.Should().HaveProperty("[1].description", TextQueryString); }); headElement.Should().ContainPath("responses").With(responseElement => { - responseElement.EnumerateObject().ShouldHaveCount(2); + responseElement.EnumerateObject().ShouldHaveCount(3); responseElement.Should().HaveProperty("200.description", "The operation completed successfully."); + responseElement.Should().HaveProperty("400.description", "The query string is invalid."); responseElement.Should().HaveProperty("404.description", "The skyscraper does not exist."); }); }); @@ -364,6 +435,7 @@ public async Task Endpoints_are_documented() patchElement.Should().ContainPath("parameters").With(parametersElement => { parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper to add spaces to."); }); @@ -386,6 +458,7 @@ public async Task Endpoints_are_documented() patchElement.Should().ContainPath("parameters").With(parametersElement => { parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper whose spaces relationship to assign."); }); @@ -408,6 +481,7 @@ public async Task Endpoints_are_documented() patchElement.Should().ContainPath("parameters").With(parametersElement => { parametersElement.EnumerateArray().ShouldHaveCount(1); + parametersElement.Should().HaveProperty("[0].in", "path"); parametersElement.Should().HaveProperty("[0].description", "The identifier of the skyscraper to remove spaces from."); }); diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json index 6042d7be81..8480de70d4 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json +++ b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json @@ -12,6 +12,21 @@ ], "summary": "Retrieves a collection of airplanes.", "operationId": "get-airplane-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found airplanes, or an empty array if none were found.", @@ -22,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -32,9 +50,27 @@ "summary": "Retrieves a collection of airplanes without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "head-airplane-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -44,6 +80,21 @@ ], "summary": "Creates a new airplane.", "operationId": "post-airplane", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the airplane to create.", "content": { @@ -73,16 +124,16 @@ "description": "The airplane was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -103,6 +154,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -116,6 +180,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -137,12 +204,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -163,6 +246,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -193,12 +289,12 @@ "204": { "description": "The airplane was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The airplane or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -250,6 +346,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -263,6 +372,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -284,12 +396,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -312,6 +440,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -325,6 +466,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -346,12 +490,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The airplane does not exist." } @@ -392,12 +552,12 @@ "204": { "description": "The flights were successfully added, which did not result in additional changes." }, - "404": { - "description": "The airplane does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The airplane does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -438,12 +598,12 @@ "204": { "description": "The flights relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The airplane does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The airplane does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -484,12 +644,12 @@ "204": { "description": "The flights were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The airplane does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The airplane does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -503,6 +663,21 @@ ], "summary": "Retrieves a collection of flight-attendants.", "operationId": "get-flight-attendant-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found flight-attendants, or an empty array if none were found.", @@ -513,6 +688,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -523,9 +701,27 @@ "summary": "Retrieves a collection of flight-attendants without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "head-flight-attendant-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -535,6 +731,21 @@ ], "summary": "Creates a new flight-attendant.", "operationId": "post-flight-attendant", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the flight-attendant to create.", "content": { @@ -564,16 +775,16 @@ "description": "The flight-attendant was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -594,6 +805,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -607,6 +831,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -628,12 +855,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -654,6 +897,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -684,12 +940,12 @@ "204": { "description": "The flight-attendant was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The flight-attendant or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -741,6 +997,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -754,6 +1023,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -775,12 +1047,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -803,6 +1091,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -816,6 +1117,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -837,12 +1141,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -883,12 +1203,12 @@ "204": { "description": "The flights were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -929,12 +1249,12 @@ "204": { "description": "The purser-on-flights relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -975,12 +1295,12 @@ "204": { "description": "The flights were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1003,6 +1323,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1016,6 +1349,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1037,12 +1373,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1065,6 +1417,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1078,6 +1443,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1099,12 +1467,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight-attendant does not exist." } @@ -1145,12 +1529,12 @@ "204": { "description": "The flights were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1191,12 +1575,12 @@ "204": { "description": "The scheduled-for-flights relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1237,12 +1621,12 @@ "204": { "description": "The flights were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight-attendant does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight-attendant does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1256,6 +1640,21 @@ ], "summary": "Retrieves a collection of flights.", "operationId": "get-flight-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "Successfully returns the found flights, or an empty array if none were found.", @@ -1266,6 +1665,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1276,9 +1678,27 @@ "summary": "Retrieves a collection of flights without returning them.", "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", "operationId": "head-flight-collection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1288,6 +1708,21 @@ ], "summary": "Creates a new flight.", "operationId": "post-flight", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], "requestBody": { "description": "The attributes and relationships of the flight to create.", "content": { @@ -1317,16 +1752,16 @@ "description": "The flight was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -1347,6 +1782,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1360,6 +1808,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1381,12 +1832,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1407,6 +1874,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "requestBody": { @@ -1437,12 +1917,12 @@ "204": { "description": "The flight was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The flight or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -1494,6 +1974,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1507,6 +2000,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1528,12 +2024,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1556,6 +2068,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1569,6 +2094,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1590,12 +2118,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1636,12 +2180,12 @@ "204": { "description": "The backup-purser relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1664,6 +2208,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1677,6 +2234,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1698,12 +2258,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1726,6 +2302,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1739,6 +2328,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1760,12 +2352,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1806,12 +2414,12 @@ "204": { "description": "The flight-attendants were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1852,12 +2460,12 @@ "204": { "description": "The cabin-crew-members relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1898,12 +2506,12 @@ "204": { "description": "The flight-attendants were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1926,6 +2534,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -1939,6 +2560,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1960,12 +2584,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -1988,6 +2628,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -2001,6 +2654,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2022,12 +2678,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2068,12 +2740,12 @@ "204": { "description": "The passengers were successfully added, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2114,12 +2786,12 @@ "204": { "description": "The passengers relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2160,12 +2832,12 @@ "204": { "description": "The passengers were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2188,6 +2860,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -2201,6 +2886,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2222,12 +2910,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2250,6 +2954,19 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { @@ -2263,6 +2980,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2284,12 +3004,28 @@ "schema": { "type": "string" } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } } ], "responses": { "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The flight does not exist." } @@ -2330,12 +3066,12 @@ "204": { "description": "The purser relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The flight does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The flight does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } diff --git a/test/OpenApiTests/OpenApiStartup.cs b/test/OpenApiTests/OpenApiStartup.cs index 6affd0bacc..e46efe63f0 100644 --- a/test/OpenApiTests/OpenApiStartup.cs +++ b/test/OpenApiTests/OpenApiStartup.cs @@ -20,6 +20,14 @@ public override void ConfigureServices(IServiceCollection services) services.AddOpenApi(mvcBuilder, SetupSwaggerGenAction); } + protected override void SetJsonApiOptions(JsonApiOptions options) + { + base.SetJsonApiOptions(options); + + options.UseRelativeLinks = true; + options.IncludeTotalResourceCount = true; + } + protected virtual void SetupSwaggerGenAction(SwaggerGenOptions options) { string documentationPath = Path.ChangeExtension(Assembly.GetExecutingAssembly().Location, ".xml"); diff --git a/test/OpenApiTests/QueryStrings/Node.cs b/test/OpenApiTests/QueryStrings/Node.cs new file mode 100644 index 0000000000..d1010b6197 --- /dev/null +++ b/test/OpenApiTests/QueryStrings/Node.cs @@ -0,0 +1,22 @@ +using JetBrains.Annotations; +using JsonApiDotNetCore.Resources; +using JsonApiDotNetCore.Resources.Annotations; + +namespace OpenApiTests.QueryStrings; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +[Resource(ControllerNamespace = "OpenApiTests.QueryStrings")] +public sealed class Node : Identifiable +{ + [Attr] + public string Name { get; set; } = null!; + + [Attr] + public string? Comment { get; set; } + + [HasOne] + public Node? Parent { get; set; } + + [HasMany] + public ISet Children { get; set; } = new HashSet(); +} diff --git a/test/OpenApiTests/QueryStrings/QueryStringFakers.cs b/test/OpenApiTests/QueryStrings/QueryStringFakers.cs new file mode 100644 index 0000000000..26b9db2798 --- /dev/null +++ b/test/OpenApiTests/QueryStrings/QueryStringFakers.cs @@ -0,0 +1,19 @@ +using Bogus; +using JetBrains.Annotations; +using TestBuildingBlocks; + +// @formatter:wrap_chained_method_calls chop_if_long +// @formatter:wrap_before_first_method_call true + +namespace OpenApiTests.QueryStrings; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class QueryStringFakers : FakerContainer +{ + private readonly Lazy> _lazyNodeFaker = new(() => new Faker() + .UseSeed(GetFakerSeed()) + .RuleFor(node => node.Name, faker => faker.Lorem.Word()) + .RuleFor(node => node.Comment, faker => faker.Lorem.Sentence())); + + public Faker Node => _lazyNodeFaker.Value; +} diff --git a/test/OpenApiTests/QueryStrings/QueryStringTests.cs b/test/OpenApiTests/QueryStrings/QueryStringTests.cs new file mode 100644 index 0000000000..bc7dfb7a6b --- /dev/null +++ b/test/OpenApiTests/QueryStrings/QueryStringTests.cs @@ -0,0 +1,85 @@ +using System.Text.Json; +using FluentAssertions; +using TestBuildingBlocks; +using Xunit; + +namespace OpenApiTests.QueryStrings; + +public sealed class QueryStringTests : IClassFixture, QueryStringsDbContext>> +{ + private readonly OpenApiTestContext, QueryStringsDbContext> _testContext; + + public QueryStringTests(OpenApiTestContext, QueryStringsDbContext> testContext) + { + _testContext = testContext; + + testContext.UseController(); + testContext.SwaggerDocumentOutputDirectory = "test/OpenApiEndToEndTests/QueryStrings"; + } + + [Theory] + [InlineData("/nodes.get")] + [InlineData("/nodes.head")] + [InlineData("/nodes.post")] + [InlineData("/nodes/{id}.get")] + [InlineData("/nodes/{id}.head")] + [InlineData("/nodes/{id}.patch")] + [InlineData("/nodes/{id}/parent.get")] + [InlineData("/nodes/{id}/parent.head")] + [InlineData("/nodes/{id}/relationships/parent.get")] + [InlineData("/nodes/{id}/relationships/parent.head")] + [InlineData("/nodes/{id}/children.get")] + [InlineData("/nodes/{id}/children.head")] + [InlineData("/nodes/{id}/relationships/children.get")] + [InlineData("/nodes/{id}/relationships/children.head")] + public async Task Endpoints_have_query_string_parameter(string endpointPath) + { + // Act + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); + + document.Should().ContainPath($"paths.{endpointPath}").With(verbElement => + { + verbElement.Should().ContainPath("parameters").With(parametersElement => + { + parametersElement.EnumerateArray().Should().ContainSingle(element => element.GetProperty("in").ValueEquals("query")).Subject.With( + parameterElement => + { + parameterElement.Should().HaveProperty("name", "query"); + + parameterElement.Should().ContainPath("schema").With(schemaElement => + { + schemaElement.Should().HaveProperty("type", "object"); + + schemaElement.Should().ContainPath("additionalProperties").With(propertiesElement => + { + propertiesElement.Should().HaveProperty("type", "string"); + propertiesElement.Should().HaveProperty("nullable", true); + }); + + schemaElement.Should().HaveProperty("example", null); + }); + }); + }); + }); + } + + [Theory] + [InlineData("/nodes/{id}.delete")] + [InlineData("/nodes/{id}/relationships/parent.patch")] + [InlineData("/nodes/{id}/relationships/children.post")] + [InlineData("/nodes/{id}/relationships/children.patch")] + [InlineData("/nodes/{id}/relationships/children.delete")] + public async Task Endpoints_do_not_have_query_string_parameter(string endpointPath) + { + // Act + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); + + document.Should().ContainPath($"paths.{endpointPath}").With(verbElement => + { + verbElement.Should().ContainPath("parameters").With(parametersElement => + { + parametersElement.EnumerateArray().Should().NotContain(element => element.GetProperty("in").ValueEquals("query")); + }); + }); + } +} diff --git a/test/OpenApiTests/QueryStrings/QueryStringsDbContext.cs b/test/OpenApiTests/QueryStrings/QueryStringsDbContext.cs new file mode 100644 index 0000000000..2be0dea6be --- /dev/null +++ b/test/OpenApiTests/QueryStrings/QueryStringsDbContext.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using TestBuildingBlocks; + +namespace OpenApiTests.QueryStrings; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class QueryStringsDbContext : TestableDbContext +{ + public DbSet Nodes => Set(); + + public QueryStringsDbContext(DbContextOptions options) + : base(options) + { + } +} diff --git a/test/TestBuildingBlocks/JsonElementAssertionExtensions.cs b/test/TestBuildingBlocks/JsonElementAssertionExtensions.cs index e53117ff23..f71ca9d84b 100644 --- a/test/TestBuildingBlocks/JsonElementAssertionExtensions.cs +++ b/test/TestBuildingBlocks/JsonElementAssertionExtensions.cs @@ -78,15 +78,15 @@ public void ContainProperty(string propertyName) .FailWith($"Expected JSON element '{escapedJson}' to contain a property named '{propertyName}'."); } - public JsonElement ContainPath(string path) + public JsonElement ContainPath(string jsonPath) { - Func elementSelector = () => _subject.SelectToken(path, true)!.Value; + Func elementSelector = () => _subject.SelectToken(jsonPath, true)!.Value; return elementSelector.Should().NotThrow().Subject; } - public void NotContainPath(string path) + public void NotContainPath(string jsonPath) { - JsonElement? pathToken = _subject.SelectToken(path); + JsonElement? pathToken = _subject.SelectToken(jsonPath); pathToken.Should().BeNull(); } @@ -116,9 +116,9 @@ public void Be(object? value) } } - public void HaveProperty(string propertyName, string propertyValue) + public void HaveProperty(string jsonPath, object? propertyValue) { - _subject.Should().ContainPath(propertyName).With(element => element.Should().Be(propertyValue)); + _subject.Should().ContainPath(jsonPath).With(element => element.Should().Be(propertyValue)); } public void ContainArrayElement(string value) From 8f0405a9e96c49ab6e09c4d21511ad43b8ee0d1c Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Mon, 30 Oct 2023 02:53:25 +0100 Subject: [PATCH 6/7] Correct the nullability of values in "meta" (`IDictionary` becomes `IDictionary`) --- src/Examples/QueryStringExample/swagger.json | 1602 +++++++++++++++++ .../OpenApiSchemaExtensions.cs | 37 + .../JsonApiSchemaGenerator.cs | 34 +- .../OpenApiSchemaExtensions.cs | 29 - .../ResourceFieldObjectSchemaBuilder.cs | 2 + .../ResourceObjectSchemaGenerator.cs | 1 + .../LegacyClient/swagger.g.json | 120 +- .../CamelCase/swagger.g.json | 70 +- .../KebabCase/swagger.g.json | 70 +- .../PascalCase/swagger.g.json | 70 +- .../ModelStateValidationOff/swagger.g.json | 75 +- .../ModelStateValidationOn/swagger.g.json | 88 +- .../ModelStateValidationOff/swagger.g.json | 88 +- .../ModelStateValidationOn/swagger.g.json | 88 +- .../QueryStrings/SparseFieldSetTests.cs | 2 - .../QueryStrings/swagger.g.json | 65 +- .../LegacyOpenApiIntegration/swagger.json | 120 +- 17 files changed, 2249 insertions(+), 312 deletions(-) create mode 100644 src/Examples/QueryStringExample/swagger.json delete mode 100644 src/JsonApiDotNetCore.OpenApi/SwaggerComponents/OpenApiSchemaExtensions.cs diff --git a/src/Examples/QueryStringExample/swagger.json b/src/Examples/QueryStringExample/swagger.json new file mode 100644 index 0000000000..819aafdb8f --- /dev/null +++ b/src/Examples/QueryStringExample/swagger.json @@ -0,0 +1,1602 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "QueryStringExample", + "version": "1.0" + }, + "paths": { + "/api/nodes": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves a collection of nodes.", + "operationId": "getNodeCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found nodes, or an empty array if none were found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodeCollectionResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves a collection of nodes without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + } + } + }, + "post": { + "tags": [ + "nodes" + ], + "summary": "Creates a new node.", + "operationId": "postNode", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "requestBody": { + "description": "The attributes and relationships of the node to create.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/nodePostRequestDocument" + } + ] + } + } + } + }, + "responses": { + "201": { + "description": "The node was successfully created, which resulted in additional changes. The newly created node is returned.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodePrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "The node was successfully created, which did not result in additional changes." + }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." + }, + "409": { + "description": "A resource type in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." + } + } + } + }, + "/api/nodes/{id}": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves an individual node by its identifier.", + "operationId": "getNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodePrimaryResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves an individual node by its identifier without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "patch": { + "tags": [ + "nodes" + ], + "summary": "Updates an existing node.", + "operationId": "patchNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to update.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "requestBody": { + "description": "The attributes and relationships of the node to update. Omitted fields are left unchanged.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/nodePatchRequestDocument" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "The node was successfully updated, which resulted in additional changes. The updated node is returned.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodePrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "The node was successfully updated, which did not result in additional changes." + }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, + "404": { + "description": "The node or a related resource does not exist." + }, + "409": { + "description": "A resource type or identifier in the request body is incompatible." + }, + "422": { + "description": "Validation of the request body failed." + } + } + }, + "delete": { + "tags": [ + "nodes" + ], + "summary": "Deletes an existing node by its identifier.", + "operationId": "deleteNode", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to delete.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "The node was successfully deleted." + }, + "404": { + "description": "The node does not exist." + } + } + } + }, + "/api/nodes/{id}/children": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related nodes of an individual node's children relationship.", + "operationId": "getNodeChildren", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related nodes to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found nodes, or an empty array if none were found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodeCollectionResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related nodes of an individual node's children relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeChildren", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related nodes to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + } + }, + "/api/nodes/{id}/relationships/children": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identities of an individual node's children relationship.", + "operationId": "getNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identities to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node identities, or an empty array if none were found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nodeIdentifierCollectionResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identities of an individual node's children relationship without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identities to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "post": { + "tags": [ + "nodes" + ], + "summary": "Adds existing nodes to the children relationship of an individual node.", + "operationId": "postNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to add nodes to.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identities of the nodes to add to the children relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The nodes were successfully added, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + }, + "patch": { + "tags": [ + "nodes" + ], + "summary": "Assigns existing nodes to the children relationship of an individual node.", + "operationId": "patchNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose children relationship to assign.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identities of the nodes to assign to the children relationship, or an empty array to clear the relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The children relationship was successfully updated, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + }, + "delete": { + "tags": [ + "nodes" + ], + "summary": "Removes existing nodes from the children relationship of an individual node.", + "operationId": "deleteNodeChildrenRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node to remove nodes from.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identities of the nodes to remove from the children relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The nodes were successfully removed, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + } + }, + "/api/nodes/{id}/parent": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node of an individual node's parent relationship.", + "operationId": "getNodeParent", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node, or `null` if it was not found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableNodeSecondaryResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node of an individual node's parent relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeParent", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + } + }, + "/api/nodes/{id}/relationships/parent": { + "get": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identity of an individual node's parent relationship.", + "operationId": "getNodeParentRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identity to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found node identity, or `null` if it was not found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableNodeIdentifierResponseDocument" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "head": { + "tags": [ + "nodes" + ], + "summary": "Retrieves the related node identity of an individual node's parent relationship without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headNodeParentRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose related node identity to retrieve.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": null + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The node does not exist." + } + } + }, + "patch": { + "tags": [ + "nodes" + ], + "summary": "Clears or assigns an existing node to the parent relationship of an individual node.", + "operationId": "patchNodeParentRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the node whose parent relationship to assign or clear.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "description": "The identity of the node to assign to the parent relationship, or `null` to clear the relationship.", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInRequest" + } + ] + } + } + } + }, + "responses": { + "204": { + "description": "The parent relationship was successfully updated, which did not result in additional changes." + }, + "400": { + "description": "The request body is missing or malformed." + }, + "404": { + "description": "The node does not exist." + }, + "409": { + "description": "A resource type in the request body is incompatible." + } + } + } + } + }, + "components": { + "schemas": { + "jsonapiObject": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "ext": { + "type": "array", + "items": { + "type": "string" + } + }, + "profile": { + "type": "array", + "items": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "linksInRelationshipObject": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "related": { + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceCollectionDocument": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceDocument": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceIdentifierCollectionDocument": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "related": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceIdentifierDocument": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + }, + "related": { + "minLength": 1, + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceObject": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false + }, + "nodeAttributesInPatchRequest": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "comment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "nodeAttributesInPostRequest": { + "required": [ + "name" + ], + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "comment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "nodeAttributesInResponse": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "comment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "nodeCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "jsonapi": { + "allOf": [ + { + "$ref": "#/components/schemas/jsonapiObject" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceCollectionDocument" + } + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeDataInResponse" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodeDataInPatchRequest": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "id": { + "minLength": 1, + "type": "string" + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeAttributesInPatchRequest" + } + ] + }, + "relationships": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeRelationshipsInPatchRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeDataInPostRequest": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeAttributesInPostRequest" + } + ] + }, + "relationships": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeRelationshipsInPostRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeDataInResponse": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "id": { + "minLength": 1, + "type": "string" + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeAttributesInResponse" + } + ] + }, + "relationships": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeRelationshipsInResponse" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceObject" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodeIdentifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeResourceType" + } + ] + }, + "id": { + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false + }, + "nodeIdentifierCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "jsonapi": { + "allOf": [ + { + "$ref": "#/components/schemas/jsonapiObject" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument" + } + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeIdentifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodePatchRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInPatchRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodePostRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInPostRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodePrimaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "jsonapi": { + "allOf": [ + { + "$ref": "#/components/schemas/jsonapiObject" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInResponse" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nodeRelationshipsInPatchRequest": { + "type": "object", + "properties": { + "parent": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInRequest" + } + ] + }, + "children": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeRelationshipsInPostRequest": { + "type": "object", + "properties": { + "parent": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInRequest" + } + ] + }, + "children": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInRequest" + } + ] + } + }, + "additionalProperties": false + }, + "nodeRelationshipsInResponse": { + "type": "object", + "properties": { + "parent": { + "allOf": [ + { + "$ref": "#/components/schemas/nullableToOneNodeInResponse" + } + ] + }, + "children": { + "allOf": [ + { + "$ref": "#/components/schemas/toManyNodeInResponse" + } + ] + } + }, + "additionalProperties": false + }, + "nodeResourceType": { + "enum": [ + "nodes" + ], + "type": "string" + }, + "nullableNodeIdentifierResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "jsonapi": { + "allOf": [ + { + "$ref": "#/components/schemas/jsonapiObject" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceIdentifierDocument" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeIdentifier" + } + ], + "nullable": true + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nullableNodeSecondaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "jsonapi": { + "allOf": [ + { + "$ref": "#/components/schemas/jsonapiObject" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInResourceDocument" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeDataInResponse" + } + ], + "nullable": true + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "nullableToOneNodeInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeIdentifier" + } + ], + "nullable": true + } + }, + "additionalProperties": false + }, + "nullableToOneNodeInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInRelationshipObject" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/nodeIdentifier" + } + ], + "nullable": true + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "toManyNodeInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeIdentifier" + } + } + }, + "additionalProperties": false + }, + "toManyNodeInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/linksInRelationshipObject" + } + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/nodeIdentifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/src/JsonApiDotNetCore.OpenApi/OpenApiSchemaExtensions.cs b/src/JsonApiDotNetCore.OpenApi/OpenApiSchemaExtensions.cs index e86c2c7423..8894d68600 100644 --- a/src/JsonApiDotNetCore.OpenApi/OpenApiSchemaExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/OpenApiSchemaExtensions.cs @@ -4,6 +4,29 @@ namespace JsonApiDotNetCore.OpenApi; internal static class OpenApiSchemaExtensions { + public static void ReorderProperties(this OpenApiSchema fullSchema, IEnumerable propertyNamesInOrder) + { + ArgumentGuard.NotNull(fullSchema); + ArgumentGuard.NotNull(propertyNamesInOrder); + + var propertiesInOrder = new Dictionary(); + + foreach (string propertyName in propertyNamesInOrder) + { + if (fullSchema.Properties.TryGetValue(propertyName, out OpenApiSchema? schema)) + { + propertiesInOrder.Add(propertyName, schema); + } + } + + if (fullSchema.Properties.Count != propertiesInOrder.Count) + { + throw new UnreachableCodeException(); + } + + fullSchema.Properties = propertiesInOrder; + } + public static OpenApiSchema UnwrapExtendedReferenceSchema(this OpenApiSchema source) { ArgumentGuard.NotNull(source); @@ -15,4 +38,18 @@ public static OpenApiSchema UnwrapExtendedReferenceSchema(this OpenApiSchema sou return source.AllOf.Single(); } + + public static void SetValuesInMetaToNullable(this OpenApiSchema fullSchema) + { + ArgumentGuard.NotNull(fullSchema); + + if (fullSchema.Properties.TryGetValue(JsonApiPropertyName.Meta, out OpenApiSchema? schemaForMeta)) + { + schemaForMeta.AdditionalProperties = new OpenApiSchema + { + Type = "object", + Nullable = true + }; + } + } } diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs index 0a3b3c01b5..f401e11f52 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs @@ -83,17 +83,17 @@ public OpenApiSchema GenerateSchema(Type modelType, SchemaRepository schemaRepos if (IsJsonApiDocument(modelType)) { - OpenApiSchema schema = GenerateJsonApiDocumentSchema(modelType); + OpenApiSchema referenceSchemaForDocument = GenerateJsonApiDocumentSchema(modelType); + OpenApiSchema fullSchemaForDocument = _schemaRepositoryAccessor.Current.Schemas[referenceSchemaForDocument.Reference.Id]; if (IsDataPropertyNullableInDocument(modelType)) { - SetDataObjectSchemaToNullable(schema); + SetDataObjectSchemaToNullable(fullSchemaForDocument); } - if (!_options.IncludeJsonApiVersion) - { - RemoveJsonApiObject(schema); - } + fullSchemaForDocument.SetValuesInMetaToNullable(); + + SetJsonApiVersion(fullSchemaForDocument); // Schema might depend on other schemas not handled by us, so should not return here. } @@ -150,20 +150,30 @@ private static OpenApiSchema CreateArrayTypeDataSchema(OpenApiSchema referenceSc }; } - private void SetDataObjectSchemaToNullable(OpenApiSchema referenceSchemaForDocument) + private void SetDataObjectSchemaToNullable(OpenApiSchema fullSchemaForDocument) { - OpenApiSchema fullSchemaForDocument = _schemaRepositoryAccessor.Current.Schemas[referenceSchemaForDocument.Reference.Id]; OpenApiSchema referenceSchemaForData = fullSchemaForDocument.Properties[JsonApiPropertyName.Data]; referenceSchemaForData.Nullable = true; fullSchemaForDocument.Properties[JsonApiPropertyName.Data] = referenceSchemaForData; } - private void RemoveJsonApiObject(OpenApiSchema referenceSchemaForDocument) + private void SetJsonApiVersion(OpenApiSchema fullSchemaForDocument) { - OpenApiSchema fullSchemaForDocument = _schemaRepositoryAccessor.Current.Schemas[referenceSchemaForDocument.Reference.Id]; - fullSchemaForDocument.Properties.Remove(JsonApiPropertyName.Jsonapi); + if (fullSchemaForDocument.Properties.TryGetValue(JsonApiPropertyName.Jsonapi, out OpenApiSchema? referenceSchemaForJsonapi)) + { + string jsonapiSchemaId = referenceSchemaForJsonapi.AllOf[0].Reference.Id; - _schemaRepositoryAccessor.Current.Schemas.Remove("jsonapi-object"); + if (!_options.IncludeJsonApiVersion) + { + fullSchemaForDocument.Properties.Remove(JsonApiPropertyName.Jsonapi); + _schemaRepositoryAccessor.Current.Schemas.Remove(jsonapiSchemaId); + } + else + { + OpenApiSchema fullSchemaForJsonapi = _schemaRepositoryAccessor.Current.Schemas[jsonapiSchemaId]; + fullSchemaForJsonapi.SetValuesInMetaToNullable(); + } + } } private static OpenApiSchema CreateExtendedReferenceSchema(OpenApiSchema referenceSchemaForResourceObject) diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/OpenApiSchemaExtensions.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/OpenApiSchemaExtensions.cs deleted file mode 100644 index d49abce453..0000000000 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/OpenApiSchemaExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.OpenApi.Models; - -namespace JsonApiDotNetCore.OpenApi.SwaggerComponents; - -internal static class OpenApiSchemaExtensions -{ - public static void ReorderProperties(this OpenApiSchema fullSchemaForResourceObject, IEnumerable propertyNamesInOrder) - { - ArgumentGuard.NotNull(fullSchemaForResourceObject); - ArgumentGuard.NotNull(propertyNamesInOrder); - - var propertiesInOrder = new Dictionary(); - - foreach (string propertyName in propertyNamesInOrder) - { - if (fullSchemaForResourceObject.Properties.TryGetValue(propertyName, out OpenApiSchema? schema)) - { - propertiesInOrder.Add(propertyName, schema); - } - } - - if (fullSchemaForResourceObject.Properties.Count != propertiesInOrder.Count) - { - throw new UnreachableCodeException(); - } - - fullSchemaForResourceObject.Properties = propertiesInOrder; - } -} diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs index e77a724bef..c04162a1dc 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs @@ -244,6 +244,8 @@ private OpenApiSchema CreateRelationshipReferenceSchema(Type relationshipSchemaT { fullSchema.Required.Remove(JsonApiPropertyName.Data); + fullSchema.SetValuesInMetaToNullable(); + fullSchema.ReorderProperties(RelationshipObjectPropertyNamesInOrder); } diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs index 98c35db59b..92764bf45f 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs @@ -59,6 +59,7 @@ public OpenApiSchema GenerateSchema(Type resourceObjectType) RemoveResourceIdIfPostResourceObject(resourceTypeInfo, fullSchemaForResourceObject); SetResourceType(fullSchemaForResourceObject, resourceTypeInfo.ResourceType); + fullSchemaForResourceObject.SetValuesInMetaToNullable(); SetResourceAttributes(fullSchemaForResourceObject, fieldObjectBuilder); diff --git a/test/OpenApiClientTests/LegacyClient/swagger.g.json b/test/OpenApiClientTests/LegacyClient/swagger.g.json index 8480de70d4..e014464a4c 100644 --- a/test/OpenApiClientTests/LegacyClient/swagger.g.json +++ b/test/OpenApiClientTests/LegacyClient/swagger.g.json @@ -3234,7 +3234,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3346,7 +3349,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3413,7 +3419,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3567,7 +3576,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3679,7 +3691,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3734,7 +3749,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3769,7 +3787,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3836,7 +3857,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3937,7 +3961,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4031,7 +4058,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4136,7 +4166,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4191,7 +4224,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4258,7 +4294,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4394,7 +4433,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4559,7 +4601,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4595,7 +4640,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4640,7 +4688,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4691,7 +4742,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4731,7 +4785,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4786,7 +4843,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4833,7 +4893,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4874,7 +4937,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4915,7 +4981,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4958,7 +5027,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json index 33c24ef622..57e4d546ce 100644 --- a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json @@ -1168,7 +1168,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1333,7 +1336,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1369,7 +1375,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1414,7 +1423,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1461,7 +1473,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1501,7 +1516,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1556,7 +1574,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1591,7 +1612,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1632,7 +1656,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1717,7 +1744,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1829,7 +1859,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1896,7 +1929,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2035,7 +2071,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2078,7 +2117,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json index 859ab008c9..97477c6b01 100644 --- a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json @@ -1168,7 +1168,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1333,7 +1336,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1369,7 +1375,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1414,7 +1423,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1461,7 +1473,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1501,7 +1516,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1556,7 +1574,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1591,7 +1612,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1632,7 +1656,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1717,7 +1744,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1829,7 +1859,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1896,7 +1929,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2035,7 +2071,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2078,7 +2117,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json index bf35e16505..22d5a1b77c 100644 --- a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json +++ b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json @@ -1168,7 +1168,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1333,7 +1336,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1369,7 +1375,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1414,7 +1423,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1461,7 +1473,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1501,7 +1516,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1556,7 +1574,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1591,7 +1612,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1632,7 +1656,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1717,7 +1744,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1829,7 +1859,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1896,7 +1929,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2035,7 +2071,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2078,7 +2117,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json index c8bf47ffa5..8f40cea0b0 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOff/swagger.g.json @@ -1503,7 +1503,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1536,7 +1539,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1584,7 +1590,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1595,31 +1604,6 @@ ], "type": "string" }, - "jsonapiObject": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "ext": { - "type": "array", - "items": { - "type": "string" - } - }, - "profile": { - "type": "array", - "items": { - "type": "string" - } - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, "linksInRelationshipObject": { "required": [ "related", @@ -1773,7 +1757,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1802,7 +1789,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1847,7 +1837,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1978,7 +1971,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2090,7 +2086,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2150,7 +2149,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2303,7 +2305,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json index 6375f83fca..1758ce7985 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOff/ModelStateValidationOn/swagger.g.json @@ -1503,7 +1503,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1536,7 +1539,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1584,7 +1590,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1612,7 +1621,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1646,32 +1658,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "jsonapiObject": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "ext": { - "type": "array", - "items": { - "type": "string" - } - }, - "profile": { - "type": "array", - "items": { - "type": "string" + "additionalProperties": { + "type": "object", + "nullable": true } - }, - "meta": { - "type": "object", - "additionalProperties": { } } }, "additionalProperties": false @@ -1829,7 +1819,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1858,7 +1851,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1903,7 +1899,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2027,7 +2026,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2139,7 +2141,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2199,7 +2204,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2351,7 +2359,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2394,7 +2405,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json index ea99c5e179..e870fc7560 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOff/swagger.g.json @@ -1981,7 +1981,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2014,7 +2017,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2062,7 +2068,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2090,7 +2099,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2124,32 +2136,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "jsonapiObject": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "ext": { - "type": "array", - "items": { - "type": "string" - } - }, - "profile": { - "type": "array", - "items": { - "type": "string" + "additionalProperties": { + "type": "object", + "nullable": true } - }, - "meta": { - "type": "object", - "additionalProperties": { } } }, "additionalProperties": false @@ -2307,7 +2297,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2336,7 +2329,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2381,7 +2377,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2534,7 +2533,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2646,7 +2648,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2706,7 +2711,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2902,7 +2910,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2945,7 +2956,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json index 90f43f0c3c..15c8c4bbc7 100644 --- a/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json +++ b/test/OpenApiClientTests/ResourceFieldValidation/NullableReferenceTypesOn/ModelStateValidationOn/swagger.g.json @@ -1981,7 +1981,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2014,7 +2017,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2062,7 +2068,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2090,7 +2099,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2124,32 +2136,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "jsonapiObject": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "ext": { - "type": "array", - "items": { - "type": "string" - } - }, - "profile": { - "type": "array", - "items": { - "type": "string" + "additionalProperties": { + "type": "object", + "nullable": true } - }, - "meta": { - "type": "object", - "additionalProperties": { } } }, "additionalProperties": false @@ -2307,7 +2297,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2336,7 +2329,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2381,7 +2377,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2528,7 +2527,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2640,7 +2642,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2700,7 +2705,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2896,7 +2904,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2939,7 +2950,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs b/test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs index 091ce758af..00d3962eeb 100644 --- a/test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs +++ b/test/OpenApiEndToEndTests/QueryStrings/SparseFieldSetTests.cs @@ -180,6 +180,4 @@ await _testContext.RunOnDatabaseAsync(async dbContext => response.Data.Id.Should().Be(node.StringId); response.Data.Attributes.Should().BeNull(); } - - // TODO: Add tests for other query string parameters. } diff --git a/test/OpenApiEndToEndTests/QueryStrings/swagger.g.json b/test/OpenApiEndToEndTests/QueryStrings/swagger.g.json index bf26054048..94c4aab9b8 100644 --- a/test/OpenApiEndToEndTests/QueryStrings/swagger.g.json +++ b/test/OpenApiEndToEndTests/QueryStrings/swagger.g.json @@ -909,31 +909,6 @@ }, "components": { "schemas": { - "jsonapiObject": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "ext": { - "type": "array", - "items": { - "type": "string" - } - }, - "profile": { - "type": "array", - "items": { - "type": "string" - } - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, "linksInRelationshipObject": { "required": [ "related", @@ -1127,7 +1102,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1239,7 +1217,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1287,7 +1268,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1347,7 +1331,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1442,7 +1429,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1471,7 +1461,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1516,7 +1509,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -1557,7 +1553,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json index 8480de70d4..e014464a4c 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json +++ b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json @@ -3234,7 +3234,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3346,7 +3349,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3413,7 +3419,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3567,7 +3576,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3679,7 +3691,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3734,7 +3749,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3769,7 +3787,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3836,7 +3857,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3937,7 +3961,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4031,7 +4058,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4136,7 +4166,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4191,7 +4224,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4258,7 +4294,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4394,7 +4433,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4559,7 +4601,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4595,7 +4640,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4640,7 +4688,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4691,7 +4742,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4731,7 +4785,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4786,7 +4843,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4833,7 +4893,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4874,7 +4937,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4915,7 +4981,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4958,7 +5027,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false From 4a827010e5a3c89f3a666558d69635a9d096c9e9 Mon Sep 17 00:00:00 2001 From: Bart Koelman <10324372+bkoelman@users.noreply.github.com> Date: Mon, 30 Oct 2023 03:24:18 +0100 Subject: [PATCH 7/7] Refresh example --- .../OpenAPIs/swagger.json | 368 ++++++++++++------ 1 file changed, 247 insertions(+), 121 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json b/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json index 3ef29cfffe..fbefa04d0c 100644 --- a/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json +++ b/src/Examples/JsonApiDotNetCoreExampleClient/OpenAPIs/swagger.json @@ -37,6 +37,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -65,6 +68,9 @@ "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -118,16 +124,16 @@ "description": "The person was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -175,6 +181,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -216,6 +225,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -280,12 +292,12 @@ "204": { "description": "The person was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The person or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -365,6 +377,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -406,6 +421,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -455,6 +473,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -496,6 +517,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -537,12 +561,12 @@ "204": { "description": "The todoItems were successfully added, which did not result in additional changes." }, - "404": { - "description": "The person does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The person does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -584,12 +608,12 @@ "204": { "description": "The assignedTodoItems relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The person does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The person does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -631,12 +655,12 @@ "204": { "description": "The todoItems were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The person does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The person does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -686,6 +710,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -727,6 +754,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -776,6 +806,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -817,6 +850,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The person does not exist." } @@ -858,12 +894,12 @@ "204": { "description": "The todoItems were successfully added, which did not result in additional changes." }, - "404": { - "description": "The person does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The person does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -905,12 +941,12 @@ "204": { "description": "The ownedTodoItems relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The person does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The person does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -952,12 +988,12 @@ "204": { "description": "The todoItems were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The person does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The person does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -996,6 +1032,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1024,6 +1063,9 @@ "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1077,16 +1119,16 @@ "description": "The tag was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -1134,6 +1176,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The tag does not exist." } @@ -1175,6 +1220,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The tag does not exist." } @@ -1239,12 +1287,12 @@ "204": { "description": "The tag was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The tag or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -1324,6 +1372,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The tag does not exist." } @@ -1365,6 +1416,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The tag does not exist." } @@ -1414,6 +1468,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The tag does not exist." } @@ -1455,6 +1512,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The tag does not exist." } @@ -1496,12 +1556,12 @@ "204": { "description": "The todoItems were successfully added, which did not result in additional changes." }, - "404": { - "description": "The tag does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The tag does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1543,12 +1603,12 @@ "204": { "description": "The todoItems relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The tag does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The tag does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1590,12 +1650,12 @@ "204": { "description": "The todoItems were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The tag does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The tag does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -1634,6 +1694,9 @@ } } } + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1662,6 +1725,9 @@ "responses": { "200": { "description": "The operation completed successfully." + }, + "400": { + "description": "The query string is invalid." } } }, @@ -1715,16 +1781,16 @@ "description": "The todoItem was successfully created, which did not result in additional changes." }, "400": { - "description": "The request body is missing or malformed." + "description": "The query string is invalid or the request body is missing or malformed." + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint." }, "409": { "description": "A resource type in the request body is incompatible." }, "422": { "description": "Validation of the request body failed." - }, - "403": { - "description": "Client-generated IDs cannot be used at this endpoint." } } } @@ -1772,6 +1838,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -1813,6 +1882,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -1877,12 +1949,12 @@ "204": { "description": "The todoItem was successfully updated, which did not result in additional changes." }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed." + }, "404": { "description": "The todoItem or a related resource does not exist." }, - "400": { - "description": "The request body is missing or malformed." - }, "409": { "description": "A resource type or identifier in the request body is incompatible." }, @@ -1962,6 +2034,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2003,6 +2078,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2052,6 +2130,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2093,6 +2174,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2134,12 +2218,12 @@ "204": { "description": "The assignee relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The todoItem does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The todoItem does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2189,6 +2273,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2230,6 +2317,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2279,6 +2369,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2320,6 +2413,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2361,12 +2457,12 @@ "204": { "description": "The owner relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The todoItem does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The todoItem does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2416,6 +2512,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2457,6 +2556,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2506,6 +2608,9 @@ } } }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2547,6 +2652,9 @@ "200": { "description": "The operation completed successfully." }, + "400": { + "description": "The query string is invalid." + }, "404": { "description": "The todoItem does not exist." } @@ -2588,12 +2696,12 @@ "204": { "description": "The tags were successfully added, which did not result in additional changes." }, - "404": { - "description": "The todoItem does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The todoItem does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2635,12 +2743,12 @@ "204": { "description": "The tags relationship was successfully updated, which did not result in additional changes." }, - "404": { - "description": "The todoItem does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The todoItem does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2682,12 +2790,12 @@ "204": { "description": "The tags were successfully removed, which did not result in additional changes." }, - "404": { - "description": "The todoItem does not exist." - }, "400": { "description": "The request body is missing or malformed." }, + "404": { + "description": "The todoItem does not exist." + }, "409": { "description": "A resource type in the request body is incompatible." } @@ -2697,31 +2805,6 @@ }, "components": { "schemas": { - "jsonapiObject": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "ext": { - "type": "array", - "items": { - "type": "string" - } - }, - "profile": { - "type": "array", - "items": { - "type": "string" - } - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, "linksInRelationshipObject": { "required": [ "related", @@ -2875,7 +2958,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2904,7 +2990,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2949,7 +3038,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -2984,10 +3076,6 @@ "additionalProperties": false }, "personAttributesInResponse": { - "required": [ - "displayName", - "lastName" - ], "type": "object", "properties": { "firstName": { @@ -3026,7 +3114,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3138,7 +3229,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3187,7 +3281,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3247,7 +3344,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3341,7 +3441,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3370,9 +3473,6 @@ "additionalProperties": false }, "tagAttributesInResponse": { - "required": [ - "name" - ], "type": "object", "properties": { "name": { @@ -3404,7 +3504,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3516,7 +3619,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3564,7 +3670,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3624,7 +3733,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3710,7 +3822,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3751,7 +3866,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3794,7 +3912,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -3846,10 +3967,6 @@ "additionalProperties": false }, "todoItemAttributesInResponse": { - "required": [ - "description", - "priority" - ], "type": "object", "properties": { "description": { @@ -3901,7 +4018,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4013,7 +4133,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4061,7 +4184,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4121,7 +4247,10 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": { + "type": "object", + "nullable": true + } } }, "additionalProperties": false @@ -4192,9 +4321,6 @@ "additionalProperties": false }, "todoItemRelationshipsInResponse": { - "required": [ - "owner" - ], "type": "object", "properties": { "owner": {