diff --git a/JsonApiDotNetCore.sln.DotSettings b/JsonApiDotNetCore.sln.DotSettings
index 6ae5a3a918..b5f9e22340 100644
--- a/JsonApiDotNetCore.sln.DotSettings
+++ b/JsonApiDotNetCore.sln.DotSettings
@@ -15,6 +15,8 @@ JsonApiDotNetCore.ArgumentGuard.NotNull($EXPR$, $NAME$);
50
False
True
+ swagger.g.json
+ swagger.json
SOLUTION
True
True
diff --git a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs
new file mode 100644
index 0000000000..1224308af9
--- /dev/null
+++ b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs
@@ -0,0 +1,25 @@
+using JetBrains.Annotations;
+
+// We cannot rely on generating ApiException as soon as we are generating multiple clients, see https://github.com/RicoSuter/NSwag/issues/2839#issuecomment-776647377.
+// Instead, we configure NSwag to point to the exception below in the generated code.
+
+// ReSharper disable once CheckNamespace
+namespace JsonApiDotNetCore.OpenApi.Client.Exceptions;
+
+[UsedImplicitly(ImplicitUseTargetFlags.Members)]
+public sealed class ApiException : Exception
+{
+ public int StatusCode { get; }
+
+ public string? Response { get; }
+
+ public IReadOnlyDictionary> Headers { get; }
+
+ public ApiException(string message, int statusCode, string? response, IReadOnlyDictionary> headers, Exception innerException)
+ : base($"{message}\n\nStatus: {statusCode}\nResponse: \n{response ?? "(null)"}", innerException)
+ {
+ StatusCode = statusCode;
+ Response = response;
+ Headers = headers;
+ }
+}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs
index 2eb2bff44d..ca04d0f853 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -6,14 +7,19 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
+// Types in the current namespace are never touched by ASP.NET ModelState validation, therefore using a non-nullable reference type for a property does not
+// imply this property is required. Instead, we use [Required] explicitly, because this is how Swashbuckle is instructed to mark properties as required.
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class NullableResourceIdentifierResponseDocument : NullableSingleData>
where TResource : IIdentifiable
{
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
+ [JsonPropertyName("jsonapi")]
public JsonapiObject Jsonapi { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceIdentifierDocument Links { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs
index 383e8301e9..93334854e0 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
internal sealed class NullableSecondaryResourceResponseDocument : NullableSingleData>
where TResource : IIdentifiable
{
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
+ [JsonPropertyName("jsonapi")]
public JsonapiObject Jsonapi { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceDocument Links { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs
index f708972a94..fd34d149d9 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -6,16 +7,17 @@
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
-// Types in the current namespace are never touched by ASP.NET ModelState validation, therefore using a non-nullable reference type for a property does not
-// imply this property is required. Instead, we use [Required] explicitly, because this is how Swashbuckle is instructed to mark properties as required.
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class PrimaryResourceResponseDocument : SingleData>
where TResource : IIdentifiable
{
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
+ [JsonPropertyName("jsonapi")]
public JsonapiObject Jsonapi { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceDocument Links { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs
index 92bbc88803..7547718523 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
internal sealed class ResourceCollectionResponseDocument : ManyData>
where TResource : IIdentifiable
{
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
+ [JsonPropertyName("jsonapi")]
public JsonapiObject Jsonapi { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceCollectionDocument Links { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs
index 1efa833988..f2b0f3a885 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
internal sealed class ResourceIdentifierCollectionResponseDocument : ManyData>
where TResource : IIdentifiable
{
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
+ [JsonPropertyName("jsonapi")]
public JsonapiObject Jsonapi { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceIdentifierCollectionDocument Links { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs
index bf87717555..1c99cbd517 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
internal sealed class ResourceIdentifierResponseDocument : SingleData>
where TResource : IIdentifiable
{
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
+ [JsonPropertyName("jsonapi")]
public JsonapiObject Jsonapi { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceIdentifierDocument Links { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs
index 1cb601c87d..c048b34dfb 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
internal sealed class SecondaryResourceResponseDocument : SingleData>
where TResource : IIdentifiable
{
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
+ [JsonPropertyName("jsonapi")]
public JsonapiObject Jsonapi { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceDocument Links { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs
index 1c7b497cb2..8ad3074e4f 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs
@@ -1,3 +1,4 @@
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects;
@@ -5,11 +6,15 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects;
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
internal sealed class JsonapiObject
{
+ [JsonPropertyName("version")]
public string Version { get; set; } = null!;
+ [JsonPropertyName("ext")]
public ICollection Ext { get; set; } = null!;
+ [JsonPropertyName("profile")]
public ICollection Profile { get; set; } = null!;
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs
index db689900b3..16b9735dac 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
@@ -7,8 +8,10 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
internal sealed class LinksInRelationshipObject
{
[Required]
+ [JsonPropertyName("self")]
public string Self { get; set; } = null!;
[Required]
+ [JsonPropertyName("related")]
public string Related { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs
index e2a96ef8e4..9ce49f9f58 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
@@ -7,16 +8,22 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
internal sealed class LinksInResourceCollectionDocument
{
[Required]
+ [JsonPropertyName("self")]
public string Self { get; set; } = null!;
+ [JsonPropertyName("describedby")]
public string Describedby { get; set; } = null!;
[Required]
+ [JsonPropertyName("first")]
public string First { get; set; } = null!;
+ [JsonPropertyName("last")]
public string Last { get; set; } = null!;
+ [JsonPropertyName("prev")]
public string Prev { get; set; } = null!;
+ [JsonPropertyName("next")]
public string Next { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs
index e22ce258bc..b83e59fa4d 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
@@ -7,7 +8,9 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
internal sealed class LinksInResourceDocument
{
[Required]
+ [JsonPropertyName("self")]
public string Self { get; set; } = null!;
+ [JsonPropertyName("describedby")]
public string Describedby { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs
index f440b118fd..a13a6175b9 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
@@ -7,19 +8,26 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
internal sealed class LinksInResourceIdentifierCollectionDocument
{
[Required]
+ [JsonPropertyName("self")]
public string Self { get; set; } = null!;
+ [JsonPropertyName("describedby")]
public string Describedby { get; set; } = null!;
[Required]
+ [JsonPropertyName("related")]
public string Related { get; set; } = null!;
[Required]
+ [JsonPropertyName("first")]
public string First { get; set; } = null!;
+ [JsonPropertyName("last")]
public string Last { get; set; } = null!;
+ [JsonPropertyName("prev")]
public string Prev { get; set; } = null!;
+ [JsonPropertyName("next")]
public string Next { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs
index 1fcca155cf..9304162d0f 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
@@ -7,10 +8,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
internal sealed class LinksInResourceIdentifierDocument
{
[Required]
+ [JsonPropertyName("self")]
public string Self { get; set; } = null!;
+ [JsonPropertyName("describedby")]
public string Describedby { get; set; } = null!;
[Required]
+ [JsonPropertyName("related")]
public string Related { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs
index f8f7de61f2..552cc703e3 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
@@ -7,5 +8,6 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
internal sealed class LinksInResourceObject
{
[Required]
+ [JsonPropertyName("self")]
public string Self { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs
index 6d345efe5f..5f80fd0f2b 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -9,5 +10,6 @@ internal abstract class ManyData
where TData : ResourceIdentifierObject
{
[Required]
+ [JsonPropertyName("data")]
public ICollection Data { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs
index 600bdf43b9..27063648cb 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -9,5 +10,6 @@ internal abstract class NullableSingleData
where TData : ResourceIdentifierObject
{
[Required]
+ [JsonPropertyName("data")]
public TData? Data { get; set; }
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs
index ed0cbd22fd..fdc45b811a 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -11,7 +12,9 @@ internal sealed class NullableToOneRelationshipInResponse : NullableS
where TResource : IIdentifiable
{
[Required]
+ [JsonPropertyName("links")]
public LinksInRelationshipObject Links { get; set; } = null!;
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs
index 381e484f0b..14380f025e 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -11,7 +12,9 @@ internal sealed class ToManyRelationshipInResponse : ManyData Meta { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs
index 962091a469..a867dffdc0 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -11,7 +12,9 @@ internal sealed class ToOneRelationshipInResponse : SingleData Meta { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs
index 5024c3ed44..783a94d647 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.Resources;
@@ -14,8 +15,10 @@ internal sealed class ResourceIdentifierObject : ResourceIdentifierOb
internal class ResourceIdentifierObject
{
[Required]
+ [JsonPropertyName("type")]
public string Type { get; set; } = null!;
[Required]
+ [JsonPropertyName("id")]
public string Id { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs
index fadb20969e..7263ededd4 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs
@@ -1,3 +1,4 @@
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.Resources;
@@ -7,7 +8,9 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
internal sealed class ResourceObjectInPatchRequest : ResourceIdentifierObject
where TResource : IIdentifiable
{
+ [JsonPropertyName("attributes")]
public AttributesInPatchRequest Attributes { get; set; } = null!;
+ [JsonPropertyName("relationships")]
public RelationshipsInPatchRequest Relationships { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs
index 71ad0f34c9..f886883b4e 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs
@@ -1,3 +1,4 @@
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.Resources;
@@ -7,7 +8,9 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
internal sealed class ResourceObjectInPostRequest : ResourceIdentifierObject
where TResource : IIdentifiable
{
+ [JsonPropertyName("attributes")]
public AttributesInPostRequest Attributes { get; set; } = null!;
+ [JsonPropertyName("relationships")]
public RelationshipsInPostRequest Relationships { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs
index 30bf3d0ff6..ae61d9822c 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links;
using JsonApiDotNetCore.Resources;
@@ -9,12 +10,16 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
internal sealed class ResourceObjectInResponse : ResourceIdentifierObject
where TResource : IIdentifiable
{
+ [JsonPropertyName("attributes")]
public AttributesInResponse Attributes { get; set; } = null!;
+ [JsonPropertyName("relationships")]
public RelationshipsInResponse Relationships { get; set; } = null!;
[Required]
+ [JsonPropertyName("links")]
public LinksInResourceObject Links { get; set; } = null!;
+ [JsonPropertyName("meta")]
public IDictionary Meta { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs
index 9ba0cd4416..019fc58c2d 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.Text.Json.Serialization;
using JetBrains.Annotations;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -9,5 +10,6 @@ internal abstract class SingleData
where TData : ResourceIdentifierObject
{
[Required]
+ [JsonPropertyName("data")]
public TData Data { get; set; } = null!;
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs
index 7e3e2572a5..9724effbd5 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs
@@ -36,7 +36,6 @@ internal sealed class JsonApiOperationIdSelector
private readonly IControllerResourceMapping _controllerResourceMapping;
private readonly JsonNamingPolicy? _namingPolicy;
- private readonly ResourceNameFormatter _formatter;
public JsonApiOperationIdSelector(IControllerResourceMapping controllerResourceMapping, JsonNamingPolicy? namingPolicy)
{
@@ -44,7 +43,6 @@ public JsonApiOperationIdSelector(IControllerResourceMapping controllerResourceM
_controllerResourceMapping = controllerResourceMapping;
_namingPolicy = namingPolicy;
- _formatter = new ResourceNameFormatter(namingPolicy);
}
public string GetOperationId(ApiDescription endpoint)
@@ -60,7 +58,7 @@ public string GetOperationId(ApiDescription endpoint)
string template = GetTemplate(primaryResourceType.ClrType, endpoint);
- return ApplyTemplate(template, primaryResourceType.ClrType, endpoint);
+ return ApplyTemplate(template, primaryResourceType, endpoint);
}
private static string GetTemplate(Type resourceClrType, ApiDescription endpoint)
@@ -107,7 +105,7 @@ private static Type GetDocumentType(Type primaryResourceClrType, ApiDescription
return type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : null;
}
- private string ApplyTemplate(string operationIdTemplate, Type resourceClrType, ApiDescription endpoint)
+ private string ApplyTemplate(string operationIdTemplate, ResourceType resourceType, ApiDescription endpoint)
{
if (endpoint.RelativePath == null || endpoint.HttpMethod == null)
{
@@ -115,20 +113,20 @@ private string ApplyTemplate(string operationIdTemplate, Type resourceClrType, A
}
string method = endpoint.HttpMethod.ToLowerInvariant();
- string primaryResourceName = _formatter.FormatResourceName(resourceClrType).Singularize();
string relationshipName = operationIdTemplate.Contains("[RelationshipName]") ? endpoint.RelativePath.Split("/").Last() : string.Empty;
// @formatter:wrap_chained_method_calls chop_always
// @formatter:keep_existing_linebreaks true
- string pascalCaseId = operationIdTemplate
+ string pascalCaseOperationId = operationIdTemplate
.Replace("[Method]", method)
- .Replace("[PrimaryResourceName]", primaryResourceName)
- .Replace("[RelationshipName]", relationshipName);
+ .Replace("[PrimaryResourceName]", resourceType.PublicName.Singularize())
+ .Replace("[RelationshipName]", relationshipName)
+ .ToPascalCase();
// @formatter:keep_existing_linebreaks restore
// @formatter:wrap_chained_method_calls restore
- return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseId) : pascalCaseId;
+ return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseOperationId) : pascalCaseOperationId;
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs
index 6c1dcf1920..2eb3f13824 100644
--- a/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs
+++ b/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs
@@ -1,3 +1,4 @@
+using System.Text.Json;
using Humanizer;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
@@ -10,42 +11,41 @@ internal sealed class JsonApiSchemaIdSelector
{
private static readonly IDictionary OpenTypeToSchemaTemplateMap = new Dictionary
{
- [typeof(ResourcePostRequestDocument<>)] = "###-post-request-document",
- [typeof(ResourcePatchRequestDocument<>)] = "###-patch-request-document",
- [typeof(ResourceObjectInPostRequest<>)] = "###-data-in-post-request",
- [typeof(AttributesInPostRequest<>)] = "###-attributes-in-post-request",
- [typeof(RelationshipsInPostRequest<>)] = "###-relationships-in-post-request",
- [typeof(ResourceObjectInPatchRequest<>)] = "###-data-in-patch-request",
- [typeof(AttributesInPatchRequest<>)] = "###-attributes-in-patch-request",
- [typeof(RelationshipsInPatchRequest<>)] = "###-relationships-in-patch-request",
- [typeof(ToOneRelationshipInRequest<>)] = "to-one-###-in-request",
- [typeof(NullableToOneRelationshipInRequest<>)] = "nullable-to-one-###-in-request",
- [typeof(ToManyRelationshipInRequest<>)] = "to-many-###-in-request",
- [typeof(PrimaryResourceResponseDocument<>)] = "###-primary-response-document",
- [typeof(SecondaryResourceResponseDocument<>)] = "###-secondary-response-document",
- [typeof(NullableSecondaryResourceResponseDocument<>)] = "nullable-###-secondary-response-document",
- [typeof(ResourceCollectionResponseDocument<>)] = "###-collection-response-document",
- [typeof(ResourceIdentifierResponseDocument<>)] = "###-identifier-response-document",
- [typeof(NullableResourceIdentifierResponseDocument<>)] = "nullable-###-identifier-response-document",
- [typeof(ResourceIdentifierCollectionResponseDocument<>)] = "###-identifier-collection-response-document",
- [typeof(ToOneRelationshipInResponse<>)] = "to-one-###-in-response",
- [typeof(NullableToOneRelationshipInResponse<>)] = "nullable-to-one-###-in-response",
- [typeof(ToManyRelationshipInResponse<>)] = "to-many-###-in-response",
- [typeof(ResourceObjectInResponse<>)] = "###-data-in-response",
- [typeof(AttributesInResponse<>)] = "###-attributes-in-response",
- [typeof(RelationshipsInResponse<>)] = "###-relationships-in-response",
- [typeof(ResourceIdentifierObject<>)] = "###-identifier"
+ [typeof(ResourcePostRequestDocument<>)] = "[ResourceName] Post Request Document",
+ [typeof(ResourcePatchRequestDocument<>)] = "[ResourceName] Patch Request Document",
+ [typeof(ResourceObjectInPostRequest<>)] = "[ResourceName] Data In Post Request",
+ [typeof(AttributesInPostRequest<>)] = "[ResourceName] Attributes In Post Request",
+ [typeof(RelationshipsInPostRequest<>)] = "[ResourceName] Relationships In Post Request",
+ [typeof(ResourceObjectInPatchRequest<>)] = "[ResourceName] Data In Patch Request",
+ [typeof(AttributesInPatchRequest<>)] = "[ResourceName] Attributes In Patch Request",
+ [typeof(RelationshipsInPatchRequest<>)] = "[ResourceName] Relationships In Patch Request",
+ [typeof(ToOneRelationshipInRequest<>)] = "To One [ResourceName] In Request",
+ [typeof(NullableToOneRelationshipInRequest<>)] = "Nullable To One [ResourceName] In Request",
+ [typeof(ToManyRelationshipInRequest<>)] = "To Many [ResourceName] In Request",
+ [typeof(PrimaryResourceResponseDocument<>)] = "[ResourceName] Primary Response Document",
+ [typeof(SecondaryResourceResponseDocument<>)] = "[ResourceName] Secondary Response Document",
+ [typeof(NullableSecondaryResourceResponseDocument<>)] = "Nullable [ResourceName] Secondary Response Document",
+ [typeof(ResourceCollectionResponseDocument<>)] = "[ResourceName] Collection Response Document",
+ [typeof(ResourceIdentifierResponseDocument<>)] = "[ResourceName] Identifier Response Document",
+ [typeof(NullableResourceIdentifierResponseDocument<>)] = "Nullable [ResourceName] Identifier Response Document",
+ [typeof(ResourceIdentifierCollectionResponseDocument<>)] = "[ResourceName] Identifier Collection Response Document",
+ [typeof(ToOneRelationshipInResponse<>)] = "To One [ResourceName] In Response",
+ [typeof(NullableToOneRelationshipInResponse<>)] = "Nullable To One [ResourceName] In Response",
+ [typeof(ToManyRelationshipInResponse<>)] = "To Many [ResourceName] In Response",
+ [typeof(ResourceObjectInResponse<>)] = "[ResourceName] Data In Response",
+ [typeof(AttributesInResponse<>)] = "[ResourceName] Attributes In Response",
+ [typeof(RelationshipsInResponse<>)] = "[ResourceName] Relationships In Response",
+ [typeof(ResourceIdentifierObject<>)] = "[ResourceName] Identifier"
};
- private readonly ResourceNameFormatter _formatter;
+ private readonly JsonNamingPolicy? _namingPolicy;
private readonly IResourceGraph _resourceGraph;
- public JsonApiSchemaIdSelector(ResourceNameFormatter formatter, IResourceGraph resourceGraph)
+ public JsonApiSchemaIdSelector(JsonNamingPolicy? namingPolicy, IResourceGraph resourceGraph)
{
- ArgumentGuard.NotNull(formatter, nameof(formatter));
ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph));
- _formatter = formatter;
+ _namingPolicy = namingPolicy;
_resourceGraph = resourceGraph;
}
@@ -62,14 +62,21 @@ public string GetSchemaId(Type type)
if (type.IsConstructedGenericType && OpenTypeToSchemaTemplateMap.ContainsKey(type.GetGenericTypeDefinition()))
{
+ Type openType = type.GetGenericTypeDefinition();
Type resourceClrType = type.GetGenericArguments().First();
- string resourceName = _formatter.FormatResourceName(resourceClrType).Singularize();
+ resourceType = _resourceGraph.FindResourceType(resourceClrType);
- string template = OpenTypeToSchemaTemplateMap[type.GetGenericTypeDefinition()];
- return template.Replace("###", resourceName);
+ if (resourceType == null)
+ {
+ throw new UnreachableCodeException();
+ }
+
+ string pascalCaseSchemaId = OpenTypeToSchemaTemplateMap[openType].Replace("[ResourceName]", resourceType.PublicName.Singularize()).ToPascalCase();
+
+ return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId;
}
- // Used for a fixed set of types, such as jsonapi-object, links-in-many-resource-document etc.
- return _formatter.FormatResourceName(type).Singularize();
+ // Used for a fixed set of types, such as JsonApiObject, LinksInResourceCollectionDocument etc.
+ return _namingPolicy != null ? _namingPolicy.ConvertName(type.Name) : type.Name;
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs
index 425617bdf8..55695102a2 100644
--- a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs
+++ b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs
@@ -55,7 +55,6 @@ private static void AddSwaggerGenerator(IServiceScope scope, IServiceCollection
var resourceGraph = scope.ServiceProvider.GetRequiredService();
var jsonApiOptions = scope.ServiceProvider.GetRequiredService();
JsonNamingPolicy? namingPolicy = jsonApiOptions.SerializerOptions.PropertyNamingPolicy;
- ResourceNameFormatter resourceNameFormatter = new(namingPolicy);
AddSchemaGenerator(services);
@@ -63,7 +62,7 @@ private static void AddSwaggerGenerator(IServiceScope scope, IServiceCollection
{
swaggerGenOptions.SupportNonNullableReferenceTypes();
SetOperationInfo(swaggerGenOptions, controllerResourceMapping, namingPolicy);
- SetSchemaIdSelector(swaggerGenOptions, resourceGraph, resourceNameFormatter);
+ SetSchemaIdSelector(swaggerGenOptions, resourceGraph, namingPolicy);
swaggerGenOptions.DocumentFilter();
setupSwaggerGenAction?.Invoke(swaggerGenOptions);
@@ -101,9 +100,9 @@ private static IList GetOperationTags(ApiDescription description, IContr
};
}
- private static void SetSchemaIdSelector(SwaggerGenOptions swaggerGenOptions, IResourceGraph resourceGraph, ResourceNameFormatter resourceNameFormatter)
+ private static void SetSchemaIdSelector(SwaggerGenOptions swaggerGenOptions, IResourceGraph resourceGraph, JsonNamingPolicy? namingPolicy)
{
- JsonApiSchemaIdSelector jsonApiObjectSchemaSelector = new(resourceNameFormatter, resourceGraph);
+ JsonApiSchemaIdSelector jsonApiObjectSchemaSelector = new(namingPolicy, resourceGraph);
swaggerGenOptions.CustomSchemaIds(type => jsonApiObjectSchemaSelector.GetSchemaId(type));
}
diff --git a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs
new file mode 100644
index 0000000000..eff26f712c
--- /dev/null
+++ b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs
@@ -0,0 +1,13 @@
+using System.Text.RegularExpressions;
+
+namespace JsonApiDotNetCore.OpenApi;
+
+internal static class StringExtensions
+{
+ private static readonly Regex Regex = new("(?:^|-|_| +)(.)", RegexOptions.Compiled);
+
+ public static string ToPascalCase(this string source)
+ {
+ return Regex.Replace(source, match => match.Groups[1].Value.ToUpper());
+ }
+}
diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs
index 4f85affcfd..a0e7159a89 100644
--- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs
@@ -38,7 +38,7 @@ public JsonApiSchemaGenerator(SchemaGenerator defaultSchemaGenerator, IResourceG
ArgumentGuard.NotNull(options, nameof(options));
_defaultSchemaGenerator = defaultSchemaGenerator;
- _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(_schemaRepositoryAccessor);
+ _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(_schemaRepositoryAccessor, options.SerializerOptions.PropertyNamingPolicy);
_resourceObjectSchemaGenerator = new ResourceObjectSchemaGenerator(defaultSchemaGenerator, resourceGraph, options, _schemaRepositoryAccessor);
}
diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs
index c8e0fe79db..d9bedc343c 100644
--- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs
@@ -1,20 +1,27 @@
+using System.Text.Json;
using Microsoft.OpenApi.Models;
namespace JsonApiDotNetCore.OpenApi.SwaggerComponents;
internal sealed class NullableReferenceSchemaGenerator
{
- private static readonly NullableReferenceSchemaStrategy NullableReferenceStrategy =
+ private const string PascalCaseNullableSchemaReferenceId = "NullValue";
+
+ private readonly NullableReferenceSchemaStrategy _nullableReferenceStrategy =
Enum.Parse(NullableReferenceSchemaStrategy.Implicit.ToString());
- private static OpenApiSchema? _referenceSchemaForNullValue;
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
+ private readonly string _nullableSchemaReferenceId;
+
+ private OpenApiSchema? _referenceSchemaForExplicitNullValue;
- public NullableReferenceSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor)
+ public NullableReferenceSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor, JsonNamingPolicy? namingPolicy)
{
ArgumentGuard.NotNull(schemaRepositoryAccessor, nameof(schemaRepositoryAccessor));
_schemaRepositoryAccessor = schemaRepositoryAccessor;
+
+ _nullableSchemaReferenceId = namingPolicy != null ? namingPolicy.ConvertName(PascalCaseNullableSchemaReferenceId) : PascalCaseNullableSchemaReferenceId;
}
public OpenApiSchema GenerateSchema(OpenApiSchema referenceSchema)
@@ -26,20 +33,13 @@ public OpenApiSchema GenerateSchema(OpenApiSchema referenceSchema)
OneOf = new List
{
referenceSchema,
- GetNullableReferenceSchema()
+ _nullableReferenceStrategy == NullableReferenceSchemaStrategy.Explicit ? GetExplicitNullSchema() : GetImplicitNullSchema()
}
};
}
- private OpenApiSchema GetNullableReferenceSchema()
- {
- return NullableReferenceStrategy == NullableReferenceSchemaStrategy.Explicit
- ? GetNullableReferenceSchemaUsingExplicitNullType()
- : GetNullableReferenceSchemaUsingImplicitNullType();
- }
-
// This approach is supported in OAS starting from v3.1. See https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-580103688
- private static OpenApiSchema GetNullableReferenceSchemaUsingExplicitNullType()
+ private static OpenApiSchema GetExplicitNullSchema()
{
return new OpenApiSchema
{
@@ -48,47 +48,57 @@ private static OpenApiSchema GetNullableReferenceSchemaUsingExplicitNullType()
}
// This approach is supported starting from OAS v3.0. See https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-487314681
- private OpenApiSchema GetNullableReferenceSchemaUsingImplicitNullType()
+ private OpenApiSchema GetImplicitNullSchema()
{
- if (_referenceSchemaForNullValue != null)
+ EnsureFullSchemaForNullValueExists();
+
+ return _referenceSchemaForExplicitNullValue ??= new OpenApiSchema
{
- return _referenceSchemaForNullValue;
- }
+ Reference = new OpenApiReference
+ {
+ Id = _nullableSchemaReferenceId,
+ Type = ReferenceType.Schema
+ }
+ };
+ }
- var fullSchemaForNullValue = new OpenApiSchema
+ private void EnsureFullSchemaForNullValueExists()
+ {
+ if (!_schemaRepositoryAccessor.Current.Schemas.ContainsKey(_nullableSchemaReferenceId))
{
- Nullable = true,
- Not = new OpenApiSchema
+ var fullSchemaForNullValue = new OpenApiSchema
{
- AnyOf = new List
+ Nullable = true,
+ Not = new OpenApiSchema
{
- new()
- {
- Type = "string"
- },
- new()
- {
- Type = "number"
- },
- new()
- {
- Type = "boolean"
- },
- new()
+ AnyOf = new List
{
- Type = "object"
+ new()
+ {
+ Type = "string"
+ },
+ new()
+ {
+ Type = "number"
+ },
+ new()
+ {
+ Type = "boolean"
+ },
+ new()
+ {
+ Type = "object"
+ },
+ new()
+ {
+ Type = "array"
+ }
},
- new()
- {
- Type = "array"
- }
- },
- Items = new OpenApiSchema()
- }
- };
-
- _referenceSchemaForNullValue = _schemaRepositoryAccessor.Current.AddDefinition("null-value", fullSchemaForNullValue);
+ Items = new OpenApiSchema()
+ }
+ };
- return _referenceSchemaForNullValue;
+ _schemaRepositoryAccessor.Current.AddDefinition(_nullableSchemaReferenceId, fullSchemaForNullValue);
+ }
}
}
diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs
index 50d56c0965..ef8c705424 100644
--- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs
+++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;
+using System.Text.Json;
using JsonApiDotNetCore.OpenApi.JsonApiObjects;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Relationships;
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -11,8 +12,6 @@ namespace JsonApiDotNetCore.OpenApi.SwaggerComponents;
internal sealed class ResourceFieldObjectSchemaBuilder
{
- private static readonly SchemaRepository ResourceSchemaRepository = new();
-
private static readonly Type[] RelationshipInResponseOpenTypes =
{
typeof(ToOneRelationshipInResponse<>),
@@ -24,11 +23,12 @@ internal sealed class ResourceFieldObjectSchemaBuilder
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
private readonly SchemaGenerator _defaultSchemaGenerator;
private readonly ResourceTypeSchemaGenerator _resourceTypeSchemaGenerator;
+ private readonly SchemaRepository _resourceSchemaRepository = new();
private readonly NullableReferenceSchemaGenerator _nullableReferenceSchemaGenerator;
private readonly IDictionary _schemasForResourceFields;
public ResourceFieldObjectSchemaBuilder(ResourceTypeInfo resourceTypeInfo, ISchemaRepositoryAccessor schemaRepositoryAccessor,
- SchemaGenerator defaultSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator)
+ SchemaGenerator defaultSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator, JsonNamingPolicy? namingPolicy)
{
ArgumentGuard.NotNull(resourceTypeInfo, nameof(resourceTypeInfo));
ArgumentGuard.NotNull(schemaRepositoryAccessor, nameof(schemaRepositoryAccessor));
@@ -40,18 +40,18 @@ public ResourceFieldObjectSchemaBuilder(ResourceTypeInfo resourceTypeInfo, ISche
_defaultSchemaGenerator = defaultSchemaGenerator;
_resourceTypeSchemaGenerator = resourceTypeSchemaGenerator;
- _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(schemaRepositoryAccessor);
+ _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(schemaRepositoryAccessor, namingPolicy);
_schemasForResourceFields = GetFieldSchemas();
}
private IDictionary GetFieldSchemas()
{
- if (!ResourceSchemaRepository.TryLookupByType(_resourceTypeInfo.ResourceType.ClrType, out OpenApiSchema referenceSchemaForResource))
+ if (!_resourceSchemaRepository.TryLookupByType(_resourceTypeInfo.ResourceType.ClrType, out OpenApiSchema referenceSchemaForResource))
{
- referenceSchemaForResource = _defaultSchemaGenerator.GenerateSchema(_resourceTypeInfo.ResourceType.ClrType, ResourceSchemaRepository);
+ referenceSchemaForResource = _defaultSchemaGenerator.GenerateSchema(_resourceTypeInfo.ResourceType.ClrType, _resourceSchemaRepository);
}
- OpenApiSchema fullSchemaForResource = ResourceSchemaRepository.Schemas[referenceSchemaForResource.Reference.Id];
+ OpenApiSchema fullSchemaForResource = _resourceSchemaRepository.Schemas[referenceSchemaForResource.Reference.Id];
return fullSchemaForResource.Properties;
}
@@ -96,7 +96,7 @@ private void AddAttributeSchemaToResourceObject(AttrAttribute attribute, OpenApi
private void ExposeSchema(OpenApiReference openApiReference, Type typeRepresentedBySchema)
{
- OpenApiSchema fullSchema = ResourceSchemaRepository.Schemas[openApiReference.Id];
+ OpenApiSchema fullSchema = _resourceSchemaRepository.Schemas[openApiReference.Id];
_schemaRepositoryAccessor.Current.AddDefinition(openApiReference.Id, fullSchema);
_schemaRepositoryAccessor.Current.RegisterType(typeRepresentedBySchema, openApiReference.Id);
}
diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs
index 540517b59c..616b98ef63 100644
--- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs
@@ -26,11 +26,12 @@ public ResourceObjectSchemaGenerator(SchemaGenerator defaultSchemaGenerator, IRe
_resourceGraph = resourceGraph;
_schemaRepositoryAccessor = schemaRepositoryAccessor;
- _resourceTypeSchemaGenerator = new ResourceTypeSchemaGenerator(schemaRepositoryAccessor, resourceGraph);
+ _resourceTypeSchemaGenerator = new ResourceTypeSchemaGenerator(schemaRepositoryAccessor, resourceGraph, options.SerializerOptions.PropertyNamingPolicy);
+
_allowClientGeneratedIds = options.AllowClientGeneratedIds;
_resourceFieldObjectSchemaBuilderFactory = resourceTypeInfo => new ResourceFieldObjectSchemaBuilder(resourceTypeInfo, schemaRepositoryAccessor,
- defaultSchemaGenerator, _resourceTypeSchemaGenerator);
+ defaultSchemaGenerator, _resourceTypeSchemaGenerator, options.SerializerOptions.PropertyNamingPolicy);
}
public OpenApiSchema GenerateSchema(Type resourceObjectType)
diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs
index d110511880..9113f3b359 100644
--- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs
+++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs
@@ -1,3 +1,5 @@
+using System.Text.Json;
+using Humanizer;
using JsonApiDotNetCore.Configuration;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
@@ -6,17 +8,20 @@ namespace JsonApiDotNetCore.OpenApi.SwaggerComponents;
internal sealed class ResourceTypeSchemaGenerator
{
+ private const string ResourceTypeSchemaIdTemplate = "[ResourceName] Resource Type";
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
private readonly IResourceGraph _resourceGraph;
+ private readonly JsonNamingPolicy? _namingPolicy;
private readonly Dictionary _resourceClrTypeSchemaCache = new();
- public ResourceTypeSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor, IResourceGraph resourceGraph)
+ public ResourceTypeSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor, IResourceGraph resourceGraph, JsonNamingPolicy? namingPolicy)
{
ArgumentGuard.NotNull(schemaRepositoryAccessor, nameof(schemaRepositoryAccessor));
ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph));
_schemaRepositoryAccessor = schemaRepositoryAccessor;
_resourceGraph = resourceGraph;
+ _namingPolicy = namingPolicy;
}
public OpenApiSchema Get(Type resourceClrType)
@@ -39,11 +44,13 @@ public OpenApiSchema Get(Type resourceClrType)
}
};
+ string schemaId = GetSchemaId(resourceType);
+
referenceSchema = new OpenApiSchema
{
Reference = new OpenApiReference
{
- Id = $"{resourceType.PublicName}-resource-type",
+ Id = schemaId,
Type = ReferenceType.Schema
}
};
@@ -53,4 +60,11 @@ public OpenApiSchema Get(Type resourceClrType)
return referenceSchema;
}
+
+ private string GetSchemaId(ResourceType resourceType)
+ {
+ string pascalCaseSchemaId = ResourceTypeSchemaIdTemplate.Replace("[ResourceName]", resourceType.PublicName.Singularize()).ToPascalCase();
+
+ return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId;
+ }
}
diff --git a/src/JsonApiDotNetCore/Serialization/Objects/JsonApiObject.cs b/src/JsonApiDotNetCore/Serialization/Objects/JsonapiObject.cs
similarity index 100%
rename from src/JsonApiDotNetCore/Serialization/Objects/JsonApiObject.cs
rename to src/JsonApiDotNetCore/Serialization/Objects/JsonapiObject.cs
diff --git a/test/OpenApiClientTests/LegacyClient/ApiResponse.cs b/test/OpenApiClientTests/LegacyClient/ApiResponse.cs
index cb00e862a4..d009d2acee 100644
--- a/test/OpenApiClientTests/LegacyClient/ApiResponse.cs
+++ b/test/OpenApiClientTests/LegacyClient/ApiResponse.cs
@@ -1,5 +1,5 @@
using JsonApiDotNetCore.OpenApi.Client;
-using OpenApiClientTests.LegacyClient.GeneratedCode;
+using JsonApiDotNetCore.OpenApi.Client.Exceptions;
#pragma warning disable AV1008 // Class should not be static
diff --git a/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs b/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs
index c164aafd0f..4582f9578d 100644
--- a/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs
+++ b/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs
@@ -22,7 +22,7 @@ public async Task Disposed_attribute_registration_for_document_does_not_affect_r
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest()
}
};
@@ -64,7 +64,7 @@ public async Task Attribute_registration_can_be_used_for_multiple_requests()
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest
{
AirtimeInHours = 100
@@ -111,7 +111,7 @@ public async Task Request_is_unaffected_by_attribute_registration_for_different_
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId1,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest()
}
};
@@ -123,7 +123,7 @@ public async Task Request_is_unaffected_by_attribute_registration_for_different_
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId2,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest()
}
};
@@ -166,7 +166,7 @@ public async Task Attribute_values_can_be_changed_after_attribute_registration()
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest
{
IsInMaintenance = true
@@ -209,7 +209,7 @@ public async Task Attribute_registration_is_unaffected_by_successive_attribute_r
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId1,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest()
}
};
@@ -218,7 +218,7 @@ public async Task Attribute_registration_is_unaffected_by_successive_attribute_r
{
Data = new AirplaneDataInPostRequest
{
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPostRequest()
}
};
@@ -260,7 +260,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId1,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest()
}
};
@@ -278,7 +278,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId2,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest
{
ManufacturedInCity = "Everett"
@@ -319,7 +319,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att
{
Data = new AirplaneDataInPostRequest
{
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPostRequest()
}
};
@@ -337,7 +337,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest
{
ManufacturedInCity = "Everett"
@@ -381,7 +381,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_attribute_re
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId1,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest()
}
};
@@ -393,7 +393,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_attribute_re
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId2,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest()
}
};
diff --git a/test/OpenApiClientTests/LegacyClient/RequestTests.cs b/test/OpenApiClientTests/LegacyClient/RequestTests.cs
index 831dfda3f7..e03e8f1015 100644
--- a/test/OpenApiClientTests/LegacyClient/RequestTests.cs
+++ b/test/OpenApiClientTests/LegacyClient/RequestTests.cs
@@ -63,7 +63,7 @@ public async Task Partial_posting_resource_with_selected_relationships_produces_
{
Data = new FlightDataInPostRequest
{
- Type = FlightsResourceType.Flights,
+ Type = FlightResourceType.Flights,
Relationships = new FlightRelationshipsInPostRequest
{
Purser = new ToOneFlightAttendantInRequest
@@ -71,7 +71,7 @@ public async Task Partial_posting_resource_with_selected_relationships_produces_
Data = new FlightAttendantIdentifier
{
Id = "bBJHu",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
},
BackupPurser = new NullableToOneFlightAttendantInRequest
@@ -79,7 +79,7 @@ public async Task Partial_posting_resource_with_selected_relationships_produces_
Data = new FlightAttendantIdentifier
{
Id = "NInmX",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
}
}
@@ -143,7 +143,7 @@ public async Task Partial_posting_resource_produces_expected_request()
{
Data = new AirplaneDataInPostRequest
{
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPostRequest
{
Name = name,
@@ -195,7 +195,7 @@ public async Task Partial_patching_resource_produces_expected_request()
Data = new AirplaneDataInPatchRequest
{
Id = airplaneId,
- Type = AirplanesResourceType.Airplanes,
+ Type = AirplaneResourceType.Airplanes,
Attributes = new AirplaneAttributesInPatchRequest
{
LastServicedAt = lastServicedAt
@@ -326,7 +326,7 @@ public async Task Patching_ToOne_relationship_produces_expected_request()
Data = new FlightAttendantIdentifier
{
Id = "bBJHu",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
};
@@ -384,12 +384,12 @@ public async Task Posting_ToMany_relationship_produces_expected_request()
{
new()
{
- Type = FlightAttendantsResourceType.FlightAttendants,
+ Type = FlightAttendantResourceType.FlightAttendants,
Id = "bBJHu"
},
new()
{
- Type = FlightAttendantsResourceType.FlightAttendants,
+ Type = FlightAttendantResourceType.FlightAttendants,
Id = "NInmX"
}
}
@@ -436,12 +436,12 @@ public async Task Patching_ToMany_relationship_produces_expected_request()
new()
{
Id = "bBJHu",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
},
new()
{
Id = "NInmX",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
}
};
@@ -487,12 +487,12 @@ public async Task Deleting_ToMany_relationship_produces_expected_request()
new()
{
Id = "bBJHu",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
},
new()
{
Id = "NInmX",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
}
};
diff --git a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs
index ee782c0adf..10f86adca5 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.Exceptions;
using OpenApiClientTests.LegacyClient.GeneratedCode;
using Xunit;
@@ -108,7 +109,7 @@ public async Task Getting_resource_collection_translates_response()
FlightDataInResponse flight = document.Data.First();
flight.Id.Should().Be(flightId);
- flight.Type.Should().Be(FlightsResourceType.Flights);
+ flight.Type.Should().Be(FlightResourceType.Flights);
flight.Links.Self.Should().Be(flightResourceLink);
flight.Meta.Should().HaveCount(1);
flight.Meta["docs"].Should().Be(flightMetaValue);
@@ -276,7 +277,7 @@ public async Task Posting_resource_translates_response()
{
Data = new FlightDataInPostRequest
{
- Type = FlightsResourceType.Flights,
+ Type = FlightResourceType.Flights,
Relationships = new FlightRelationshipsInPostRequest
{
Purser = new ToOneFlightAttendantInRequest
@@ -284,7 +285,7 @@ public async Task Posting_resource_translates_response()
Data = new FlightAttendantIdentifier
{
Id = flightAttendantId,
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
}
}
@@ -297,7 +298,7 @@ public async Task Posting_resource_translates_response()
document.Data.Relationships.Purser.Data.Id.Should().Be(flightAttendantId);
document.Data.Relationships.CabinCrewMembers.Data.Should().HaveCount(1);
document.Data.Relationships.CabinCrewMembers.Data.First().Id.Should().Be(flightAttendantId);
- document.Data.Relationships.CabinCrewMembers.Data.First().Type.Should().Be(FlightAttendantsResourceType.FlightAttendants);
+ document.Data.Relationships.CabinCrewMembers.Data.First().Type.Should().Be(FlightAttendantResourceType.FlightAttendants);
document.Data.Relationships.Passengers.Data.Should().BeEmpty();
}
@@ -329,12 +330,12 @@ public async Task Patching_resource_with_side_effects_translates_response()
Data = new FlightDataInPatchRequest
{
Id = flightId,
- Type = FlightsResourceType.Flights
+ Type = FlightResourceType.Flights
}
});
// Assert
- document.Data.Type.Should().Be(FlightsResourceType.Flights);
+ document.Data.Type.Should().Be(FlightResourceType.Flights);
document.Data.Attributes.Should().BeNull();
document.Data.Relationships.Should().BeNull();
}
@@ -354,7 +355,7 @@ public async Task Patching_resource_without_side_effects_translates_response()
Data = new FlightDataInPatchRequest
{
Id = flightId,
- Type = FlightsResourceType.Flights
+ Type = FlightResourceType.Flights
}
}));
@@ -537,7 +538,7 @@ public async Task Getting_ToOne_relationship_translates_response()
// Assert
document.Data.Should().NotBeNull();
document.Data.Id.Should().Be(purserId);
- document.Data.Type.Should().Be(FlightAttendantsResourceType.FlightAttendants);
+ document.Data.Type.Should().Be(FlightAttendantResourceType.FlightAttendants);
}
[Fact]
@@ -553,7 +554,7 @@ public async Task Patching_ToOne_relationship_translates_response()
Data = new FlightAttendantIdentifier
{
Id = "Adk2a",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
});
}
@@ -591,9 +592,9 @@ public async Task Getting_ToMany_relationship_translates_response()
// Assert
document.Data.Should().HaveCount(2);
document.Data.First().Id.Should().Be(flightAttendantId1);
- document.Data.First().Type.Should().Be(FlightAttendantsResourceType.FlightAttendants);
+ document.Data.First().Type.Should().Be(FlightAttendantResourceType.FlightAttendants);
document.Data.Last().Id.Should().Be(flightAttendantId2);
- document.Data.Last().Type.Should().Be(FlightAttendantsResourceType.FlightAttendants);
+ document.Data.Last().Type.Should().Be(FlightAttendantResourceType.FlightAttendants);
}
[Fact]
@@ -611,12 +612,12 @@ public async Task Posting_ToMany_relationship_produces_empty_response()
new()
{
Id = "Adk2a",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
},
new()
{
Id = "Un37k",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
}
});
@@ -640,12 +641,12 @@ public async Task Patching_ToMany_relationship_produces_empty_response()
new()
{
Id = "Adk2a",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
},
new()
{
Id = "Un37k",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
}
});
@@ -669,12 +670,12 @@ public async Task Deleting_ToMany_relationship_produces_empty_response()
new()
{
Id = "Adk2a",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
},
new()
{
Id = "Un37k",
- Type = FlightAttendantsResourceType.FlightAttendants
+ Type = FlightAttendantResourceType.FlightAttendants
}
}
});
diff --git a/test/OpenApiClientTests/LegacyClient/swagger.g.json b/test/OpenApiClientTests/LegacyClient/swagger.g.json
new file mode 100644
index 0000000000..03575fe1d2
--- /dev/null
+++ b/test/OpenApiClientTests/LegacyClient/swagger.g.json
@@ -0,0 +1,3363 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "OpenApiTests",
+ "version": "1.0"
+ },
+ "paths": {
+ "/api/v1/airplanes": {
+ "get": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "get-airplane-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "head-airplane-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "post-airplane",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-post-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/airplanes/{id}": {
+ "get": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "get-airplane",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "head-airplane",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "patch-airplane",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-patch-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/airplane-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "delete-airplane",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/airplanes/{id}/flights": {
+ "get": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "get-airplane-flights",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "head-airplane-flights",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/airplanes/{id}/relationships/flights": {
+ "get": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "get-airplane-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "head-airplane-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "post-airplane-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "patch-airplane-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "airplanes"
+ ],
+ "operationId": "delete-airplane-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flight-attendants": {
+ "get": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "get-flight-attendant-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "head-flight-attendant-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "post-flight-attendant",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-post-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flight-attendants/{id}": {
+ "get": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "get-flight-attendant",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "head-flight-attendant",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "patch-flight-attendant",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-patch-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "delete-flight-attendant",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flight-attendants/{id}/purser-on-flights": {
+ "get": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "get-flight-attendant-purser-on-flights",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "head-flight-attendant-purser-on-flights",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flight-attendants/{id}/relationships/purser-on-flights": {
+ "get": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "get-flight-attendant-purser-on-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "head-flight-attendant-purser-on-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "post-flight-attendant-purser-on-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "patch-flight-attendant-purser-on-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "delete-flight-attendant-purser-on-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flight-attendants/{id}/scheduled-for-flights": {
+ "get": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "get-flight-attendant-scheduled-for-flights",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "head-flight-attendant-scheduled-for-flights",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flight-attendants/{id}/relationships/scheduled-for-flights": {
+ "get": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "get-flight-attendant-scheduled-for-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "head-flight-attendant-scheduled-for-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "post-flight-attendant-scheduled-for-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "patch-flight-attendant-scheduled-for-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "flight-attendants"
+ ],
+ "operationId": "delete-flight-attendant-scheduled-for-flights-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flights": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "post-flight",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-post-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "patch-flight",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-patch-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "delete-flight",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/backup-purser": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-backup-purser",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-flight-attendant-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-backup-purser",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-flight-attendant-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/relationships/backup-purser": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-backup-purser-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-flight-attendant-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-backup-purser-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-flight-attendant-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "patch-flight-backup-purser-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/cabin-crew-members": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-cabin-crew-members",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-cabin-crew-members",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/relationships/cabin-crew-members": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-cabin-crew-members-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-cabin-crew-members-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "post-flight-cabin-crew-members-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-attendant-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "patch-flight-cabin-crew-members-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-attendant-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "delete-flight-cabin-crew-members-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-flight-attendant-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/passengers": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-passengers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/passenger-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-passengers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/passenger-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/relationships/passengers": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-passengers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/passenger-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-passengers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/passenger-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "post-flight-passengers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-passenger-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "patch-flight-passengers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-passenger-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "delete-flight-passengers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-passenger-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/purser": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-purser",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-purser",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/flights/{id}/relationships/purser": {
+ "get": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "get-flight-purser-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "head-flight-purser-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/flight-attendant-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "flights"
+ ],
+ "operationId": "patch-flight-purser-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-one-flight-attendant-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "aircraft-kind": {
+ "enum": [
+ "Turboprops",
+ "LightJet",
+ "MidSizeJet",
+ "JumboJet"
+ ],
+ "type": "string"
+ },
+ "airline": {
+ "enum": [
+ "DeltaAirLines",
+ "LufthansaGroup",
+ "AirFranceKlm"
+ ],
+ "type": "string"
+ },
+ "airplane-attributes-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "maxLength": 255,
+ "type": "string"
+ },
+ "serial-number": {
+ "maxLength": 16,
+ "type": "string",
+ "nullable": true
+ },
+ "airtime-in-hours": {
+ "type": "integer",
+ "format": "int32",
+ "nullable": true
+ },
+ "last-serviced-at": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ },
+ "is-in-maintenance": {
+ "type": "boolean"
+ },
+ "manufactured-in-city": {
+ "maxLength": 85,
+ "type": "string",
+ "nullable": true
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-attributes-in-post-request": {
+ "required": [
+ "name"
+ ],
+ "type": "object",
+ "properties": {
+ "name": {
+ "maxLength": 255,
+ "type": "string"
+ },
+ "serial-number": {
+ "maxLength": 16,
+ "type": "string",
+ "nullable": true
+ },
+ "airtime-in-hours": {
+ "type": "integer",
+ "format": "int32",
+ "nullable": true
+ },
+ "last-serviced-at": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-attributes-in-response": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "maxLength": 255,
+ "type": "string"
+ },
+ "serial-number": {
+ "maxLength": 16,
+ "type": "string",
+ "nullable": true
+ },
+ "airtime-in-hours": {
+ "type": "integer",
+ "format": "int32",
+ "nullable": true
+ },
+ "last-serviced-at": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ },
+ "manufactured-at": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "is-in-maintenance": {
+ "type": "boolean"
+ },
+ "manufactured-in-city": {
+ "maxLength": 85,
+ "type": "string",
+ "nullable": true
+ },
+ "kind": {
+ "$ref": "#/components/schemas/aircraft-kind"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/airplane-data-in-response"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-data-in-patch-request": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/airplane-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/airplane-attributes-in-patch-request"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/airplane-relationships-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-data-in-post-request": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/airplane-resource-type"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/airplane-attributes-in-post-request"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/airplane-relationships-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-data-in-response": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/airplane-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/airplane-attributes-in-response"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/airplane-relationships-in-response"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-patch-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/airplane-data-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-post-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/airplane-data-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-primary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/airplane-data-in-response"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-relationships-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-relationships-in-post-request": {
+ "type": "object",
+ "properties": {
+ "flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-relationships-in-response": {
+ "type": "object",
+ "properties": {
+ "flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-response"
+ }
+ },
+ "additionalProperties": false
+ },
+ "airplane-resource-type": {
+ "enum": [
+ "airplanes"
+ ],
+ "type": "string"
+ },
+ "cabin-area": {
+ "enum": [
+ "FirstClass",
+ "BusinessClass",
+ "EconomyClass"
+ ],
+ "type": "string"
+ },
+ "flight-attendant-attributes-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "email-address": {
+ "type": "string",
+ "format": "email"
+ },
+ "age": {
+ "maximum": 75,
+ "minimum": 18,
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-attributes-in-post-request": {
+ "required": [
+ "email-address",
+ "profile-image-url"
+ ],
+ "type": "object",
+ "properties": {
+ "email-address": {
+ "type": "string",
+ "format": "email"
+ },
+ "age": {
+ "maximum": 75,
+ "minimum": 18,
+ "type": "integer",
+ "format": "int32"
+ },
+ "profile-image-url": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-attributes-in-response": {
+ "type": "object",
+ "properties": {
+ "email-address": {
+ "type": "string",
+ "format": "email"
+ },
+ "age": {
+ "maximum": 75,
+ "minimum": 18,
+ "type": "integer",
+ "format": "int32"
+ },
+ "profile-image-url": {
+ "type": "string",
+ "format": "uri"
+ },
+ "distance-traveled-in-kilometers": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-attendant-data-in-response"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-data-in-patch-request": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/flight-attendant-attributes-in-patch-request"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/flight-attendant-relationships-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-data-in-post-request": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/flight-attendant-attributes-in-post-request"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/flight-attendant-relationships-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-data-in-response": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/flight-attendant-attributes-in-response"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/flight-attendant-relationships-in-response"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-identifier": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-identifier-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-identifier-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-patch-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-attendant-data-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-post-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-attendant-data-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-primary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-attendant-data-in-response"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-relationships-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "scheduled-for-flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ },
+ "purser-on-flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-relationships-in-post-request": {
+ "type": "object",
+ "properties": {
+ "scheduled-for-flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ },
+ "purser-on-flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-relationships-in-response": {
+ "type": "object",
+ "properties": {
+ "scheduled-for-flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-response"
+ },
+ "purser-on-flights": {
+ "$ref": "#/components/schemas/to-many-flight-in-response"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attendant-resource-type": {
+ "enum": [
+ "flight-attendants"
+ ],
+ "type": "string"
+ },
+ "flight-attendant-secondary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-attendant-data-in-response"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attributes-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "final-destination": {
+ "maxLength": 40,
+ "type": "string"
+ },
+ "stop-over-destination": {
+ "maxLength": 2000,
+ "type": "string",
+ "nullable": true
+ },
+ "operated-by": {
+ "$ref": "#/components/schemas/airline"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-attributes-in-response": {
+ "type": "object",
+ "properties": {
+ "final-destination": {
+ "maxLength": 40,
+ "type": "string"
+ },
+ "stop-over-destination": {
+ "maxLength": 2000,
+ "type": "string",
+ "nullable": true
+ },
+ "operated-by": {
+ "$ref": "#/components/schemas/airline"
+ },
+ "departs-at": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ },
+ "arrives-at": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ },
+ "services-on-board": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-data-in-response"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-data-in-patch-request": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/flight-attributes-in-patch-request"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/flight-relationships-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-data-in-post-request": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-resource-type"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/flight-relationships-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-data-in-response": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/flight-attributes-in-response"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/flight-relationships-in-response"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-identifier": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/flight-resource-type"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-identifier-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-identifier"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-patch-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-data-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-post-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-data-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-primary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-data-in-response"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-relationships-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "cabin-crew-members": {
+ "$ref": "#/components/schemas/to-many-flight-attendant-in-request"
+ },
+ "purser": {
+ "$ref": "#/components/schemas/to-one-flight-attendant-in-request"
+ },
+ "backup-purser": {
+ "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-request"
+ },
+ "passengers": {
+ "$ref": "#/components/schemas/to-many-passenger-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-relationships-in-post-request": {
+ "required": [
+ "purser"
+ ],
+ "type": "object",
+ "properties": {
+ "cabin-crew-members": {
+ "$ref": "#/components/schemas/to-many-flight-attendant-in-request"
+ },
+ "purser": {
+ "$ref": "#/components/schemas/to-one-flight-attendant-in-request"
+ },
+ "backup-purser": {
+ "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-request"
+ },
+ "passengers": {
+ "$ref": "#/components/schemas/to-many-passenger-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-relationships-in-response": {
+ "type": "object",
+ "properties": {
+ "cabin-crew-members": {
+ "$ref": "#/components/schemas/to-many-flight-attendant-in-response"
+ },
+ "purser": {
+ "$ref": "#/components/schemas/to-one-flight-attendant-in-response"
+ },
+ "backup-purser": {
+ "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-response"
+ },
+ "passengers": {
+ "$ref": "#/components/schemas/to-many-passenger-in-response"
+ }
+ },
+ "additionalProperties": false
+ },
+ "flight-resource-type": {
+ "enum": [
+ "flights"
+ ],
+ "type": "string"
+ },
+ "jsonapi-object": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string"
+ },
+ "ext": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "profile": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-relationship-object": {
+ "required": [
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-collection-document": {
+ "required": [
+ "first",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "first": {
+ "type": "string"
+ },
+ "last": {
+ "type": "string"
+ },
+ "prev": {
+ "type": "string"
+ },
+ "next": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-document": {
+ "required": [
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-identifier-collection-document": {
+ "required": [
+ "first",
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ },
+ "first": {
+ "type": "string"
+ },
+ "last": {
+ "type": "string"
+ },
+ "prev": {
+ "type": "string"
+ },
+ "next": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-identifier-document": {
+ "required": [
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-object": {
+ "required": [
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "null-value": {
+ "not": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "object"
+ },
+ {
+ "type": "array"
+ }
+ ],
+ "items": { }
+ },
+ "nullable": true
+ },
+ "nullable-flight-attendant-identifier-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullable-flight-attendant-secondary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/flight-attendant-data-in-response"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullable-to-one-flight-attendant-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullable-to-one-flight-attendant-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "passenger-attributes-in-response": {
+ "type": "object",
+ "properties": {
+ "full-name": {
+ "type": "string",
+ "nullable": true
+ },
+ "cabin-area": {
+ "$ref": "#/components/schemas/cabin-area"
+ }
+ },
+ "additionalProperties": false
+ },
+ "passenger-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/passenger-data-in-response"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "passenger-data-in-response": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/passenger-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/passenger-attributes-in-response"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "passenger-identifier": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/passenger-resource-type"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "passenger-identifier-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/passenger-identifier"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "passenger-resource-type": {
+ "enum": [
+ "passengers"
+ ],
+ "type": "string"
+ },
+ "to-many-flight-attendant-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-many-flight-attendant-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ }
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-many-flight-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-identifier"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-many-flight-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/flight-identifier"
+ }
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-many-passenger-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/passenger-identifier"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-many-passenger-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/passenger-identifier"
+ }
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-one-flight-attendant-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-one-flight-attendant-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/flight-attendant-identifier"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/OpenApiClientTests/NamingConventions/CamelCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConventions/CamelCase/GeneratedTypesTests.cs
new file mode 100644
index 0000000000..003c452c98
--- /dev/null
+++ b/test/OpenApiClientTests/NamingConventions/CamelCase/GeneratedTypesTests.cs
@@ -0,0 +1,77 @@
+using OpenApiClientTests.NamingConventions.CamelCase.GeneratedCode;
+using Xunit;
+
+namespace OpenApiClientTests.NamingConventions.CamelCase;
+
+public sealed class GeneratedTypesTests
+{
+ [Fact]
+ public void Generated_code_is_named_as_expected()
+ {
+ _ = nameof(CamelCaseClient.GetSupermarketCollectionAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketCollectionAsync);
+ _ = nameof(CamelCaseClient.PostSupermarketAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketAsync);
+ _ = nameof(CamelCaseClient.PatchSupermarketAsync);
+ _ = nameof(CamelCaseClient.DeleteSupermarketAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(CamelCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketCashiersAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketCashiersAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync);
+ _ = nameof(CamelCaseClient.PostSupermarketCashiersRelationshipAsync);
+ _ = nameof(CamelCaseClient.PatchSupermarketCashiersRelationshipAsync);
+ _ = nameof(CamelCaseClient.DeleteSupermarketCashiersRelationshipAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketStoreManagerAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketStoreManagerAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync);
+ _ = nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync);
+ _ = nameof(CamelCaseClient.PatchSupermarketStoreManagerRelationshipAsync);
+
+ _ = nameof(SupermarketCollectionResponseDocument);
+ _ = nameof(LinksInResourceCollectionDocument);
+ _ = nameof(JsonapiObject);
+ _ = nameof(SupermarketDataInResponse);
+ _ = nameof(SupermarketResourceType.Supermarkets);
+ _ = nameof(SupermarketAttributesInResponse.NameOfCity);
+ _ = nameof(SupermarketRelationshipsInResponse.StoreManager);
+ _ = nameof(SupermarketRelationshipsInResponse.BackupStoreManager);
+ _ = nameof(LinksInResourceObject);
+ _ = nameof(SupermarketType);
+ _ = nameof(CamelCaseClient.GetSupermarketAsync);
+ _ = nameof(ToOneStaffMemberInResponse);
+ _ = nameof(NullableToOneStaffMemberInResponse);
+ _ = nameof(ToManyStaffMemberInResponse);
+ _ = nameof(LinksInRelationshipObject);
+ _ = nameof(StaffMemberIdentifier);
+ _ = nameof(StaffMemberResourceType.StaffMembers);
+ _ = nameof(SupermarketPrimaryResponseDocument);
+ _ = nameof(LinksInResourceDocument);
+ _ = nameof(StaffMemberSecondaryResponseDocument);
+ _ = nameof(StaffMemberDataInResponse);
+ _ = nameof(StaffMemberAttributesInResponse);
+ _ = nameof(NullableStaffMemberSecondaryResponseDocument);
+ _ = nameof(StaffMemberCollectionResponseDocument);
+ _ = nameof(StaffMemberIdentifierResponseDocument);
+ _ = nameof(LinksInResourceIdentifierDocument);
+ _ = nameof(NullableStaffMemberIdentifierResponseDocument);
+ _ = nameof(StaffMemberIdentifierCollectionResponseDocument);
+ _ = nameof(LinksInResourceIdentifierCollectionDocument);
+ _ = nameof(SupermarketPostRequestDocument);
+ _ = nameof(SupermarketDataInPostRequest);
+ _ = nameof(SupermarketAttributesInPostRequest);
+ _ = nameof(SupermarketRelationshipsInPostRequest);
+ _ = nameof(ToOneStaffMemberInRequest);
+ _ = nameof(NullableToOneStaffMemberInRequest);
+ _ = nameof(ToManyStaffMemberInRequest);
+ _ = nameof(SupermarketPatchRequestDocument);
+ _ = nameof(SupermarketDataInPatchRequest);
+ _ = nameof(SupermarketAttributesInPatchRequest);
+ _ = nameof(SupermarketRelationshipsInPatchRequest);
+ }
+}
diff --git a/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json
new file mode 100644
index 0000000000..2eaac9303c
--- /dev/null
+++ b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json
@@ -0,0 +1,1466 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "OpenApiTests",
+ "version": "1.0"
+ },
+ "paths": {
+ "/supermarkets": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarketCollection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarketCollection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "postSupermarket",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketPostRequestDocument"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patchSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketPatchRequestDocument"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "deleteSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/backupStoreManager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarketBackupStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullableStaffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarketBackupStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullableStaffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/relationships/backupStoreManager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarketBackupStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullableStaffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarketBackupStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullableStaffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patchSupermarketBackupStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullableToOneStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/cashiers": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarketCashiers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarketCashiers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/relationships/cashiers": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberIdentifierCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberIdentifierCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "postSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/toManyStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patchSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/toManyStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "deleteSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/toManyStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/storeManager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarketStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarketStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/relationships/storeManager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "getSupermarketStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "headSupermarketStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patchSupermarketStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/toOneStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ }
+ },
+ "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": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "linksInResourceCollectionDocument": {
+ "required": [
+ "first",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "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": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "linksInResourceIdentifierCollectionDocument": {
+ "required": [
+ "first",
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ },
+ "first": {
+ "type": "string"
+ },
+ "last": {
+ "type": "string"
+ },
+ "prev": {
+ "type": "string"
+ },
+ "next": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "linksInResourceIdentifierDocument": {
+ "required": [
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "linksInResourceObject": {
+ "required": [
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullValue": {
+ "not": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "object"
+ },
+ {
+ "type": "array"
+ }
+ ],
+ "items": { }
+ },
+ "nullable": true
+ },
+ "nullableStaffMemberIdentifierResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ },
+ {
+ "$ref": "#/components/schemas/nullValue"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceIdentifierDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullableStaffMemberSecondaryResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staffMemberDataInResponse"
+ },
+ {
+ "$ref": "#/components/schemas/nullValue"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullableToOneStaffMemberInRequest": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ },
+ {
+ "$ref": "#/components/schemas/nullValue"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullableToOneStaffMemberInResponse": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ },
+ {
+ "$ref": "#/components/schemas/nullValue"
+ }
+ ]
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInRelationshipObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "staffMemberAttributesInResponse": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "age": {
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staffMemberCollectionResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staffMemberDataInResponse"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceCollectionDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staffMemberDataInResponse": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/staffMemberResourceType"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/staffMemberAttributesInResponse"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "staffMemberIdentifier": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/staffMemberResourceType"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staffMemberIdentifierCollectionResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staffMemberIdentifierResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceIdentifierDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staffMemberResourceType": {
+ "enum": [
+ "staffMembers"
+ ],
+ "type": "string"
+ },
+ "staffMemberSecondaryResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staffMemberDataInResponse"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketAttributesInPatchRequest": {
+ "type": "object",
+ "properties": {
+ "nameOfCity": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/supermarketType"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketAttributesInPostRequest": {
+ "required": [
+ "nameOfCity"
+ ],
+ "type": "object",
+ "properties": {
+ "nameOfCity": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/supermarketType"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketAttributesInResponse": {
+ "type": "object",
+ "properties": {
+ "nameOfCity": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/supermarketType"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketCollectionResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/supermarketDataInResponse"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceCollectionDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketDataInPatchRequest": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/supermarketResourceType"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/supermarketAttributesInPatchRequest"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/supermarketRelationshipsInPatchRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketDataInPostRequest": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/supermarketResourceType"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/supermarketAttributesInPostRequest"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/supermarketRelationshipsInPostRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketDataInResponse": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/supermarketResourceType"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/supermarketAttributesInResponse"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/supermarketRelationshipsInResponse"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketPatchRequestDocument": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/supermarketDataInPatchRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketPostRequestDocument": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/supermarketDataInPostRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketPrimaryResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/supermarketDataInResponse"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInResourceDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketRelationshipsInPatchRequest": {
+ "type": "object",
+ "properties": {
+ "storeManager": {
+ "$ref": "#/components/schemas/toOneStaffMemberInRequest"
+ },
+ "backupStoreManager": {
+ "$ref": "#/components/schemas/nullableToOneStaffMemberInRequest"
+ },
+ "cashiers": {
+ "$ref": "#/components/schemas/toManyStaffMemberInRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketRelationshipsInPostRequest": {
+ "required": [
+ "storeManager"
+ ],
+ "type": "object",
+ "properties": {
+ "storeManager": {
+ "$ref": "#/components/schemas/toOneStaffMemberInRequest"
+ },
+ "backupStoreManager": {
+ "$ref": "#/components/schemas/nullableToOneStaffMemberInRequest"
+ },
+ "cashiers": {
+ "$ref": "#/components/schemas/toManyStaffMemberInRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketRelationshipsInResponse": {
+ "type": "object",
+ "properties": {
+ "storeManager": {
+ "$ref": "#/components/schemas/toOneStaffMemberInResponse"
+ },
+ "backupStoreManager": {
+ "$ref": "#/components/schemas/nullableToOneStaffMemberInResponse"
+ },
+ "cashiers": {
+ "$ref": "#/components/schemas/toManyStaffMemberInResponse"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarketResourceType": {
+ "enum": [
+ "supermarkets"
+ ],
+ "type": "string"
+ },
+ "supermarketType": {
+ "enum": [
+ "Traditional",
+ "Budget",
+ "Warehouse"
+ ],
+ "type": "string"
+ },
+ "toManyStaffMemberInRequest": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "toManyStaffMemberInResponse": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ }
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInRelationshipObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "toOneStaffMemberInRequest": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ }
+ },
+ "additionalProperties": false
+ },
+ "toOneStaffMemberInResponse": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staffMemberIdentifier"
+ },
+ "links": {
+ "$ref": "#/components/schemas/linksInRelationshipObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs
new file mode 100644
index 0000000000..f4884561fd
--- /dev/null
+++ b/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs
@@ -0,0 +1,77 @@
+using OpenApiClientTests.NamingConventions.KebabCase.GeneratedCode;
+using Xunit;
+
+namespace OpenApiClientTests.NamingConventions.KebabCase;
+
+public sealed class GeneratedTypesTests
+{
+ [Fact]
+ public void Generated_code_is_named_as_expected()
+ {
+ _ = nameof(KebabCaseClient.GetSupermarketCollectionAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketCollectionAsync);
+ _ = nameof(KebabCaseClient.PostSupermarketAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketAsync);
+ _ = nameof(KebabCaseClient.PatchSupermarketAsync);
+ _ = nameof(KebabCaseClient.DeleteSupermarketAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(KebabCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketCashiersAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketCashiersAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync);
+ _ = nameof(KebabCaseClient.PostSupermarketCashiersRelationshipAsync);
+ _ = nameof(KebabCaseClient.PatchSupermarketCashiersRelationshipAsync);
+ _ = nameof(KebabCaseClient.DeleteSupermarketCashiersRelationshipAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketStoreManagerAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketStoreManagerAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync);
+ _ = nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync);
+ _ = nameof(KebabCaseClient.PatchSupermarketStoreManagerRelationshipAsync);
+
+ _ = nameof(SupermarketCollectionResponseDocument);
+ _ = nameof(LinksInResourceCollectionDocument);
+ _ = nameof(JsonapiObject);
+ _ = nameof(SupermarketDataInResponse);
+ _ = nameof(SupermarketResourceType.Supermarkets);
+ _ = nameof(SupermarketAttributesInResponse.NameOfCity);
+ _ = nameof(SupermarketRelationshipsInResponse.StoreManager);
+ _ = nameof(SupermarketRelationshipsInResponse.BackupStoreManager);
+ _ = nameof(LinksInResourceObject);
+ _ = nameof(SupermarketType);
+ _ = nameof(KebabCaseClient.GetSupermarketAsync);
+ _ = nameof(ToOneStaffMemberInResponse);
+ _ = nameof(NullableToOneStaffMemberInResponse);
+ _ = nameof(ToManyStaffMemberInResponse);
+ _ = nameof(LinksInRelationshipObject);
+ _ = nameof(StaffMemberIdentifier);
+ _ = nameof(StaffMemberResourceType.StaffMembers);
+ _ = nameof(SupermarketPrimaryResponseDocument);
+ _ = nameof(LinksInResourceDocument);
+ _ = nameof(StaffMemberSecondaryResponseDocument);
+ _ = nameof(StaffMemberDataInResponse);
+ _ = nameof(StaffMemberAttributesInResponse);
+ _ = nameof(NullableStaffMemberSecondaryResponseDocument);
+ _ = nameof(StaffMemberCollectionResponseDocument);
+ _ = nameof(StaffMemberIdentifierResponseDocument);
+ _ = nameof(LinksInResourceIdentifierDocument);
+ _ = nameof(NullableStaffMemberIdentifierResponseDocument);
+ _ = nameof(StaffMemberIdentifierCollectionResponseDocument);
+ _ = nameof(LinksInResourceIdentifierCollectionDocument);
+ _ = nameof(SupermarketPostRequestDocument);
+ _ = nameof(SupermarketDataInPostRequest);
+ _ = nameof(SupermarketAttributesInPostRequest);
+ _ = nameof(SupermarketRelationshipsInPostRequest);
+ _ = nameof(ToOneStaffMemberInRequest);
+ _ = nameof(NullableToOneStaffMemberInRequest);
+ _ = nameof(ToManyStaffMemberInRequest);
+ _ = nameof(SupermarketPatchRequestDocument);
+ _ = nameof(SupermarketDataInPatchRequest);
+ _ = nameof(SupermarketAttributesInPatchRequest);
+ _ = nameof(SupermarketRelationshipsInPatchRequest);
+ }
+}
diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json
new file mode 100644
index 0000000000..1013e900a8
--- /dev/null
+++ b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json
@@ -0,0 +1,1466 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "OpenApiTests",
+ "version": "1.0"
+ },
+ "paths": {
+ "/supermarkets": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket-collection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "post-supermarket",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-post-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-primary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patch-supermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-patch-request-document"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/supermarket-primary-response-document"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "delete-supermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/backup-store-manager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket-backup-store-manager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket-backup-store-manager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/relationships/backup-store-manager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket-backup-store-manager-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket-backup-store-manager-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patch-supermarket-backup-store-manager-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/cashiers": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket-cashiers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket-cashiers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/relationships/cashiers": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket-cashiers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket-cashiers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-identifier-collection-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "post-supermarket-cashiers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-staff-member-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patch-supermarket-cashiers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-staff-member-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "delete-supermarket-cashiers-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-many-staff-member-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/store-manager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket-store-manager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket-store-manager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-secondary-response-document"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/supermarkets/{id}/relationships/store-manager": {
+ "get": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "get-supermarket-store-manager-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "head-supermarket-store-manager-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/staff-member-identifier-response-document"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "supermarkets"
+ ],
+ "operationId": "patch-supermarket-store-manager-relationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/to-one-staff-member-in-request"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "jsonapi-object": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string"
+ },
+ "ext": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "profile": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-relationship-object": {
+ "required": [
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-collection-document": {
+ "required": [
+ "first",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "first": {
+ "type": "string"
+ },
+ "last": {
+ "type": "string"
+ },
+ "prev": {
+ "type": "string"
+ },
+ "next": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-document": {
+ "required": [
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-identifier-collection-document": {
+ "required": [
+ "first",
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ },
+ "first": {
+ "type": "string"
+ },
+ "last": {
+ "type": "string"
+ },
+ "prev": {
+ "type": "string"
+ },
+ "next": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-identifier-document": {
+ "required": [
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "links-in-resource-object": {
+ "required": [
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "null-value": {
+ "not": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "object"
+ },
+ {
+ "type": "array"
+ }
+ ],
+ "items": { }
+ },
+ "nullable": true
+ },
+ "nullable-staff-member-identifier-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullable-staff-member-secondary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staff-member-data-in-response"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullable-to-one-staff-member-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "nullable-to-one-staff-member-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ },
+ {
+ "$ref": "#/components/schemas/null-value"
+ }
+ ]
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "staff-member-attributes-in-response": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "age": {
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staff-member-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staff-member-data-in-response"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staff-member-data-in-response": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/staff-member-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/staff-member-attributes-in-response"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "staff-member-identifier": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/staff-member-resource-type"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staff-member-identifier-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staff-member-identifier-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-identifier-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "staff-member-resource-type": {
+ "enum": [
+ "staff-members"
+ ],
+ "type": "string"
+ },
+ "staff-member-secondary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staff-member-data-in-response"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-attributes-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "name-of-city": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/supermarket-type"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-attributes-in-post-request": {
+ "required": [
+ "name-of-city"
+ ],
+ "type": "object",
+ "properties": {
+ "name-of-city": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/supermarket-type"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-attributes-in-response": {
+ "type": "object",
+ "properties": {
+ "name-of-city": {
+ "type": "string"
+ },
+ "kind": {
+ "$ref": "#/components/schemas/supermarket-type"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-collection-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/supermarket-data-in-response"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-collection-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-data-in-patch-request": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/supermarket-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/supermarket-attributes-in-patch-request"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/supermarket-relationships-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-data-in-post-request": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/supermarket-resource-type"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/supermarket-attributes-in-post-request"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/supermarket-relationships-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-data-in-response": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/supermarket-resource-type"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/supermarket-attributes-in-response"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/supermarket-relationships-in-response"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-patch-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/supermarket-data-in-patch-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-post-request-document": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/supermarket-data-in-post-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-primary-response-document": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/supermarket-data-in-response"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/jsonapi-object"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-resource-document"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-relationships-in-patch-request": {
+ "type": "object",
+ "properties": {
+ "store-manager": {
+ "$ref": "#/components/schemas/to-one-staff-member-in-request"
+ },
+ "backup-store-manager": {
+ "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request"
+ },
+ "cashiers": {
+ "$ref": "#/components/schemas/to-many-staff-member-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-relationships-in-post-request": {
+ "required": [
+ "store-manager"
+ ],
+ "type": "object",
+ "properties": {
+ "store-manager": {
+ "$ref": "#/components/schemas/to-one-staff-member-in-request"
+ },
+ "backup-store-manager": {
+ "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request"
+ },
+ "cashiers": {
+ "$ref": "#/components/schemas/to-many-staff-member-in-request"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-relationships-in-response": {
+ "type": "object",
+ "properties": {
+ "store-manager": {
+ "$ref": "#/components/schemas/to-one-staff-member-in-response"
+ },
+ "backup-store-manager": {
+ "$ref": "#/components/schemas/nullable-to-one-staff-member-in-response"
+ },
+ "cashiers": {
+ "$ref": "#/components/schemas/to-many-staff-member-in-response"
+ }
+ },
+ "additionalProperties": false
+ },
+ "supermarket-resource-type": {
+ "enum": [
+ "supermarkets"
+ ],
+ "type": "string"
+ },
+ "supermarket-type": {
+ "enum": [
+ "Traditional",
+ "Budget",
+ "Warehouse"
+ ],
+ "type": "string"
+ },
+ "to-many-staff-member-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-many-staff-member-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ }
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-one-staff-member-in-request": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ }
+ },
+ "additionalProperties": false
+ },
+ "to-one-staff-member-in-response": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/staff-member-identifier"
+ },
+ "links": {
+ "$ref": "#/components/schemas/links-in-relationship-object"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/OpenApiClientTests/NamingConventions/PascalCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConventions/PascalCase/GeneratedTypesTests.cs
new file mode 100644
index 0000000000..9ec0325e58
--- /dev/null
+++ b/test/OpenApiClientTests/NamingConventions/PascalCase/GeneratedTypesTests.cs
@@ -0,0 +1,77 @@
+using OpenApiClientTests.NamingConventions.PascalCase.GeneratedCode;
+using Xunit;
+
+namespace OpenApiClientTests.NamingConventions.PascalCase;
+
+public sealed class GeneratedTypesTests
+{
+ [Fact]
+ public void Generated_code_is_named_as_expected()
+ {
+ _ = nameof(PascalCaseClient.GetSupermarketCollectionAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketCollectionAsync);
+ _ = nameof(PascalCaseClient.PostSupermarketAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketAsync);
+ _ = nameof(PascalCaseClient.PatchSupermarketAsync);
+ _ = nameof(PascalCaseClient.DeleteSupermarketAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(PascalCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketCashiersAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketCashiersAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync);
+ _ = nameof(PascalCaseClient.PostSupermarketCashiersRelationshipAsync);
+ _ = nameof(PascalCaseClient.PatchSupermarketCashiersRelationshipAsync);
+ _ = nameof(PascalCaseClient.DeleteSupermarketCashiersRelationshipAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketStoreManagerAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketStoreManagerAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync);
+ _ = nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync);
+ _ = nameof(PascalCaseClient.PatchSupermarketStoreManagerRelationshipAsync);
+
+ _ = nameof(SupermarketCollectionResponseDocument);
+ _ = nameof(LinksInResourceCollectionDocument);
+ _ = nameof(JsonapiObject);
+ _ = nameof(SupermarketDataInResponse);
+ _ = nameof(SupermarketResourceType.Supermarkets);
+ _ = nameof(SupermarketAttributesInResponse.NameOfCity);
+ _ = nameof(SupermarketRelationshipsInResponse.StoreManager);
+ _ = nameof(SupermarketRelationshipsInResponse.BackupStoreManager);
+ _ = nameof(LinksInResourceObject);
+ _ = nameof(SupermarketType);
+ _ = nameof(PascalCaseClient.GetSupermarketAsync);
+ _ = nameof(ToOneStaffMemberInResponse);
+ _ = nameof(NullableToOneStaffMemberInResponse);
+ _ = nameof(ToManyStaffMemberInResponse);
+ _ = nameof(LinksInRelationshipObject);
+ _ = nameof(StaffMemberIdentifier);
+ _ = nameof(StaffMemberResourceType.StaffMembers);
+ _ = nameof(SupermarketPrimaryResponseDocument);
+ _ = nameof(LinksInResourceDocument);
+ _ = nameof(StaffMemberSecondaryResponseDocument);
+ _ = nameof(StaffMemberDataInResponse);
+ _ = nameof(StaffMemberAttributesInResponse);
+ _ = nameof(NullableStaffMemberSecondaryResponseDocument);
+ _ = nameof(StaffMemberCollectionResponseDocument);
+ _ = nameof(StaffMemberIdentifierResponseDocument);
+ _ = nameof(LinksInResourceIdentifierDocument);
+ _ = nameof(NullableStaffMemberIdentifierResponseDocument);
+ _ = nameof(StaffMemberIdentifierCollectionResponseDocument);
+ _ = nameof(LinksInResourceIdentifierCollectionDocument);
+ _ = nameof(SupermarketPostRequestDocument);
+ _ = nameof(SupermarketDataInPostRequest);
+ _ = nameof(SupermarketAttributesInPostRequest);
+ _ = nameof(SupermarketRelationshipsInPostRequest);
+ _ = nameof(ToOneStaffMemberInRequest);
+ _ = nameof(NullableToOneStaffMemberInRequest);
+ _ = nameof(ToManyStaffMemberInRequest);
+ _ = nameof(SupermarketPatchRequestDocument);
+ _ = nameof(SupermarketDataInPatchRequest);
+ _ = nameof(SupermarketAttributesInPatchRequest);
+ _ = nameof(SupermarketRelationshipsInPatchRequest);
+ }
+}
diff --git a/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json
new file mode 100644
index 0000000000..3906897de4
--- /dev/null
+++ b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json
@@ -0,0 +1,1466 @@
+{
+ "openapi": "3.0.1",
+ "info": {
+ "title": "OpenApiTests",
+ "version": "1.0"
+ },
+ "paths": {
+ "/Supermarkets": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarketCollection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarketCollection",
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "PostSupermarket",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketPostRequestDocument"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/Supermarkets/{id}": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "PatchSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketPatchRequestDocument"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "DeleteSupermarket",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/Supermarkets/{id}/BackupStoreManager": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarketBackupStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/NullableStaffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarketBackupStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/NullableStaffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/Supermarkets/{id}/relationships/BackupStoreManager": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarketBackupStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/NullableStaffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarketBackupStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/NullableStaffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "PatchSupermarketBackupStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/NullableToOneStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/Supermarkets/{id}/Cashiers": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarketCashiers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarketCashiers",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/Supermarkets/{id}/relationships/Cashiers": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberIdentifierCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberIdentifierCollectionResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "PostSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/ToManyStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "PatchSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/ToManyStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "DeleteSupermarketCashiersRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/ToManyStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ },
+ "/Supermarkets/{id}/StoreManager": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarketStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarketStoreManager",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberSecondaryResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/Supermarkets/{id}/relationships/StoreManager": {
+ "get": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "GetSupermarketStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "head": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "HeadSupermarketStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Success",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/StaffMemberIdentifierResponseDocument"
+ }
+ }
+ }
+ }
+ }
+ },
+ "patch": {
+ "tags": [
+ "Supermarkets"
+ ],
+ "operationId": "PatchSupermarketStoreManagerRelationship",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/ToOneStaffMemberInRequest"
+ }
+ }
+ }
+ },
+ "responses": {
+ "204": {
+ "description": "Success"
+ }
+ }
+ }
+ }
+ },
+ "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": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "LinksInResourceCollectionDocument": {
+ "required": [
+ "first",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "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": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "LinksInResourceIdentifierCollectionDocument": {
+ "required": [
+ "first",
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ },
+ "first": {
+ "type": "string"
+ },
+ "last": {
+ "type": "string"
+ },
+ "prev": {
+ "type": "string"
+ },
+ "next": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "LinksInResourceIdentifierDocument": {
+ "required": [
+ "related",
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ },
+ "describedby": {
+ "type": "string"
+ },
+ "related": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "LinksInResourceObject": {
+ "required": [
+ "self"
+ ],
+ "type": "object",
+ "properties": {
+ "self": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "NullValue": {
+ "not": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "number"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "object"
+ },
+ {
+ "type": "array"
+ }
+ ],
+ "items": { }
+ },
+ "nullable": true
+ },
+ "NullableStaffMemberIdentifierResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ },
+ {
+ "$ref": "#/components/schemas/NullValue"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceIdentifierDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "NullableStaffMemberSecondaryResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/StaffMemberDataInResponse"
+ },
+ {
+ "$ref": "#/components/schemas/NullValue"
+ }
+ ]
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "NullableToOneStaffMemberInRequest": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ },
+ {
+ "$ref": "#/components/schemas/NullValue"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "NullableToOneStaffMemberInResponse": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ },
+ {
+ "$ref": "#/components/schemas/NullValue"
+ }
+ ]
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInRelationshipObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "StaffMemberAttributesInResponse": {
+ "type": "object",
+ "properties": {
+ "Name": {
+ "type": "string"
+ },
+ "Age": {
+ "type": "integer",
+ "format": "int32"
+ }
+ },
+ "additionalProperties": false
+ },
+ "StaffMemberCollectionResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/StaffMemberDataInResponse"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceCollectionDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "StaffMemberDataInResponse": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/StaffMemberResourceType"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/StaffMemberAttributesInResponse"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "StaffMemberIdentifier": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/StaffMemberResourceType"
+ },
+ "id": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "StaffMemberIdentifierCollectionResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceIdentifierCollectionDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "StaffMemberIdentifierResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceIdentifierDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "StaffMemberResourceType": {
+ "enum": [
+ "StaffMembers"
+ ],
+ "type": "string"
+ },
+ "StaffMemberSecondaryResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/StaffMemberDataInResponse"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketAttributesInPatchRequest": {
+ "type": "object",
+ "properties": {
+ "NameOfCity": {
+ "type": "string"
+ },
+ "Kind": {
+ "$ref": "#/components/schemas/SupermarketType"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketAttributesInPostRequest": {
+ "required": [
+ "NameOfCity"
+ ],
+ "type": "object",
+ "properties": {
+ "NameOfCity": {
+ "type": "string"
+ },
+ "Kind": {
+ "$ref": "#/components/schemas/SupermarketType"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketAttributesInResponse": {
+ "type": "object",
+ "properties": {
+ "NameOfCity": {
+ "type": "string"
+ },
+ "Kind": {
+ "$ref": "#/components/schemas/SupermarketType"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketCollectionResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/SupermarketDataInResponse"
+ }
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceCollectionDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketDataInPatchRequest": {
+ "required": [
+ "id",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/SupermarketResourceType"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/SupermarketAttributesInPatchRequest"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/SupermarketRelationshipsInPatchRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketDataInPostRequest": {
+ "required": [
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/SupermarketResourceType"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/SupermarketAttributesInPostRequest"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/SupermarketRelationshipsInPostRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketDataInResponse": {
+ "required": [
+ "id",
+ "links",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "#/components/schemas/SupermarketResourceType"
+ },
+ "id": {
+ "type": "string"
+ },
+ "attributes": {
+ "$ref": "#/components/schemas/SupermarketAttributesInResponse"
+ },
+ "relationships": {
+ "$ref": "#/components/schemas/SupermarketRelationshipsInResponse"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketPatchRequestDocument": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/SupermarketDataInPatchRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketPostRequestDocument": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/SupermarketDataInPostRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketPrimaryResponseDocument": {
+ "required": [
+ "data",
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/SupermarketDataInResponse"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ },
+ "jsonapi": {
+ "$ref": "#/components/schemas/JsonapiObject"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInResourceDocument"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketRelationshipsInPatchRequest": {
+ "type": "object",
+ "properties": {
+ "StoreManager": {
+ "$ref": "#/components/schemas/ToOneStaffMemberInRequest"
+ },
+ "BackupStoreManager": {
+ "$ref": "#/components/schemas/NullableToOneStaffMemberInRequest"
+ },
+ "Cashiers": {
+ "$ref": "#/components/schemas/ToManyStaffMemberInRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketRelationshipsInPostRequest": {
+ "required": [
+ "StoreManager"
+ ],
+ "type": "object",
+ "properties": {
+ "StoreManager": {
+ "$ref": "#/components/schemas/ToOneStaffMemberInRequest"
+ },
+ "BackupStoreManager": {
+ "$ref": "#/components/schemas/NullableToOneStaffMemberInRequest"
+ },
+ "Cashiers": {
+ "$ref": "#/components/schemas/ToManyStaffMemberInRequest"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketRelationshipsInResponse": {
+ "type": "object",
+ "properties": {
+ "StoreManager": {
+ "$ref": "#/components/schemas/ToOneStaffMemberInResponse"
+ },
+ "BackupStoreManager": {
+ "$ref": "#/components/schemas/NullableToOneStaffMemberInResponse"
+ },
+ "Cashiers": {
+ "$ref": "#/components/schemas/ToManyStaffMemberInResponse"
+ }
+ },
+ "additionalProperties": false
+ },
+ "SupermarketResourceType": {
+ "enum": [
+ "Supermarkets"
+ ],
+ "type": "string"
+ },
+ "SupermarketType": {
+ "enum": [
+ "Traditional",
+ "Budget",
+ "Warehouse"
+ ],
+ "type": "string"
+ },
+ "ToManyStaffMemberInRequest": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "ToManyStaffMemberInResponse": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ }
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInRelationshipObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ },
+ "ToOneStaffMemberInRequest": {
+ "required": [
+ "data"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ }
+ },
+ "additionalProperties": false
+ },
+ "ToOneStaffMemberInResponse": {
+ "required": [
+ "links"
+ ],
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/StaffMemberIdentifier"
+ },
+ "links": {
+ "$ref": "#/components/schemas/LinksInRelationshipObject"
+ },
+ "meta": {
+ "type": "object",
+ "additionalProperties": { }
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/OpenApiClientTests/OpenApiClientTests.csproj b/test/OpenApiClientTests/OpenApiClientTests.csproj
index 005d70d251..3f54c161b8 100644
--- a/test/OpenApiClientTests/OpenApiClientTests.csproj
+++ b/test/OpenApiClientTests/OpenApiClientTests.csproj
@@ -3,6 +3,12 @@
$(TargetFrameworkName)
+
+
+ PreserveNewest
+
+
+
@@ -28,22 +34,33 @@
-
+
OpenApiClientTests.LegacyClient.GeneratedCode
OpenApiClient
+ OpenApiClient.cs
NSwagCSharp
- /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal
+ /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions
+
+
+ OpenApiClientTests.NamingConventions.KebabCase.GeneratedCode
+ KebabCaseClient
+ KebabCaseClient.cs
+ NSwagCSharp
+ /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions
+
+
+ OpenApiClientTests.NamingConventions.CamelCase.GeneratedCode
+ CamelCaseClient
+ CamelCaseClient.cs
+ NSwagCSharp
+ /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions
+
+
+ OpenApiClientTests.NamingConventions.PascalCase.GeneratedCode
+ PascalCaseClient
+ PascalCaseClient.cs
+ NSwagCSharp
+ /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/test/OpenApiClientTests/xunit.runner.json b/test/OpenApiClientTests/xunit.runner.json
new file mode 100644
index 0000000000..8f5f10571b
--- /dev/null
+++ b/test/OpenApiClientTests/xunit.runner.json
@@ -0,0 +1,5 @@
+{
+ "parallelizeAssembly": false,
+ "parallelizeTestCollections": false,
+ "maxParallelThreads": 1
+}
diff --git a/test/OpenApiTests/JsonElementExtensions.cs b/test/OpenApiTests/JsonElementExtensions.cs
new file mode 100644
index 0000000000..d8dc7d4e20
--- /dev/null
+++ b/test/OpenApiTests/JsonElementExtensions.cs
@@ -0,0 +1,79 @@
+using System.Text.Json;
+using BlushingPenguin.JsonPath;
+using FluentAssertions;
+using FluentAssertions.Execution;
+using TestBuildingBlocks;
+
+namespace OpenApiTests;
+
+internal static class JsonElementExtensions
+{
+ public static JsonElementAssertions Should(this JsonElement source)
+ {
+ return new JsonElementAssertions(source);
+ }
+
+ public static JsonElement ShouldContainPath(this JsonElement source, string path)
+ {
+ Func elementSelector = () => source.SelectToken(path, true)!.Value;
+ return elementSelector.Should().NotThrow().Subject;
+ }
+
+ public static void ShouldBeString(this JsonElement source, string value)
+ {
+ source.ValueKind.Should().Be(JsonValueKind.String);
+ source.GetString().Should().Be(value);
+ }
+
+ public static SchemaReferenceIdContainer ShouldBeSchemaReferenceId(this JsonElement source, string value)
+ {
+ source.ValueKind.Should().Be(JsonValueKind.String);
+
+ string? jsonElementValue = source.GetString();
+ jsonElementValue.ShouldNotBeNull();
+
+ string schemaReferenceId = jsonElementValue.Split('/').Last();
+ schemaReferenceId.Should().Be(value);
+
+ return new SchemaReferenceIdContainer(value);
+ }
+
+ public sealed class SchemaReferenceIdContainer
+ {
+ public string SchemaReferenceId { get; }
+
+ public SchemaReferenceIdContainer(string schemaReferenceId)
+ {
+ SchemaReferenceId = schemaReferenceId;
+ }
+ }
+
+ public sealed class JsonElementAssertions : JsonElementAssertions
+ {
+ public JsonElementAssertions(JsonElement subject)
+ : base(subject)
+ {
+ }
+ }
+
+ public class JsonElementAssertions
+ where TAssertions : JsonElementAssertions
+ {
+ private readonly JsonElement _subject;
+
+ protected JsonElementAssertions(JsonElement subject)
+ {
+ _subject = subject;
+ }
+
+ public void ContainProperty(string propertyName)
+ {
+ string json = _subject.ToString();
+
+ string escapedJson = json.Replace("{", "{{").Replace("}", "}}");
+
+ Execute.Assertion.ForCondition(_subject.TryGetProperty(propertyName, out _))
+ .FailWith($"Expected JSON element '{escapedJson}' to contain a property named '{propertyName}'.");
+ }
+ }
+}
diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs
index 3d253e2dc9..a6da96f37b 100644
--- a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs
+++ b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs
@@ -1,53 +1,44 @@
using System.Reflection;
+using System.Text.Json;
using FluentAssertions;
using TestBuildingBlocks;
using Xunit;
namespace OpenApiTests.LegacyOpenApiIntegration;
-public sealed class LegacyOpenApiIntegrationTests
- : IntegrationTestContext, LegacyIntegrationDbContext>
+public sealed class LegacyOpenApiIntegrationTests : OpenApiTestContext, LegacyIntegrationDbContext>
{
public LegacyOpenApiIntegrationTests()
{
UseController();
UseController();
UseController();
+
+ SwaggerDocumentOutputPath = "test/OpenApiClientTests/LegacyClient";
}
[Fact]
- public async Task Retrieved_document_matches_expected_document()
+ public async Task Retrieved_swagger_document_matches_expected_document()
{
- // Arrange
- const string embeddedResourceName = $"{nameof(OpenApiTests)}.{nameof(LegacyOpenApiIntegration)}.swagger.json";
- string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName);
- const string requestUrl = "swagger/v1/swagger.json";
-
// Act
- string actualDocument = await GetAsync(requestUrl);
+ JsonElement jsonElement = await GetSwaggerDocumentAsync();
// Assert
- actualDocument.Should().BeJson(expectedDocument);
- }
-
- private async Task GetAsync(string requestUrl)
- {
- var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
-
- using HttpClient client = Factory.CreateClient();
- HttpResponseMessage responseMessage = await client.SendAsync(request);
-
- return await responseMessage.Content.ReadAsStringAsync();
+ string expectedJsonText = await GetExpectedSwaggerDocumentAsync();
+ string actualJsonText = jsonElement.ToString();
+ actualJsonText.Should().BeJson(expectedJsonText);
}
- private static async Task LoadEmbeddedResourceAsync(string name)
+ private static async Task GetExpectedSwaggerDocumentAsync()
{
+ const string embeddedResourceName = $"{nameof(OpenApiTests)}.{nameof(LegacyOpenApiIntegration)}.swagger.json";
var assembly = Assembly.GetExecutingAssembly();
- await using Stream? stream = assembly.GetManifestResourceStream(name);
+
+ await using Stream? stream = assembly.GetManifestResourceStream(embeddedResourceName);
if (stream == null)
{
- throw new Exception($"Failed to load embedded resource '{name}'. Set Build Action to Embedded Resource in properties.");
+ throw new Exception($"Failed to load embedded resource '{embeddedResourceName}'. Set Build Action to Embedded Resource in properties.");
}
using var reader = new StreamReader(stream);
diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json
index ac62204a53..3fb80fb856 100644
--- a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json
+++ b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json
@@ -2043,7 +2043,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/airplanes-resource-type"
+ "$ref": "#/components/schemas/airplane-resource-type"
},
"id": {
"type": "string"
@@ -2064,7 +2064,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/airplanes-resource-type"
+ "$ref": "#/components/schemas/airplane-resource-type"
},
"attributes": {
"$ref": "#/components/schemas/airplane-attributes-in-post-request"
@@ -2084,7 +2084,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/airplanes-resource-type"
+ "$ref": "#/components/schemas/airplane-resource-type"
},
"id": {
"type": "string"
@@ -2179,7 +2179,7 @@
},
"additionalProperties": false
},
- "airplanes-resource-type": {
+ "airplane-resource-type": {
"enum": [
"airplanes"
],
@@ -2291,7 +2291,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flight-attendants-resource-type"
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
},
"id": {
"type": "string"
@@ -2312,7 +2312,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flight-attendants-resource-type"
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
},
"attributes": {
"$ref": "#/components/schemas/flight-attendant-attributes-in-post-request"
@@ -2332,7 +2332,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flight-attendants-resource-type"
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
},
"id": {
"type": "string"
@@ -2361,7 +2361,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flight-attendants-resource-type"
+ "$ref": "#/components/schemas/flight-attendant-resource-type"
},
"id": {
"type": "string"
@@ -2501,6 +2501,12 @@
},
"additionalProperties": false
},
+ "flight-attendant-resource-type": {
+ "enum": [
+ "flight-attendants"
+ ],
+ "type": "string"
+ },
"flight-attendant-secondary-response-document": {
"required": [
"data",
@@ -2524,12 +2530,6 @@
},
"additionalProperties": false
},
- "flight-attendants-resource-type": {
- "enum": [
- "flight-attendants"
- ],
- "type": "string"
- },
"flight-attributes-in-patch-request": {
"type": "object",
"properties": {
@@ -2616,7 +2616,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flights-resource-type"
+ "$ref": "#/components/schemas/flight-resource-type"
},
"id": {
"type": "string"
@@ -2637,7 +2637,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flights-resource-type"
+ "$ref": "#/components/schemas/flight-resource-type"
},
"relationships": {
"$ref": "#/components/schemas/flight-relationships-in-post-request"
@@ -2654,7 +2654,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flights-resource-type"
+ "$ref": "#/components/schemas/flight-resource-type"
},
"id": {
"type": "string"
@@ -2683,7 +2683,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/flights-resource-type"
+ "$ref": "#/components/schemas/flight-resource-type"
},
"id": {
"type": "string"
@@ -2821,7 +2821,7 @@
},
"additionalProperties": false
},
- "flights-resource-type": {
+ "flight-resource-type": {
"enum": [
"flights"
],
@@ -3150,7 +3150,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/passengers-resource-type"
+ "$ref": "#/components/schemas/passenger-resource-type"
},
"id": {
"type": "string"
@@ -3176,7 +3176,7 @@
"type": "object",
"properties": {
"type": {
- "$ref": "#/components/schemas/passengers-resource-type"
+ "$ref": "#/components/schemas/passenger-resource-type"
},
"id": {
"type": "string"
@@ -3210,7 +3210,7 @@
},
"additionalProperties": false
},
- "passengers-resource-type": {
+ "passenger-resource-type": {
"enum": [
"passengers"
],
@@ -3360,4 +3360,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseNamingConventionStartup.cs
new file mode 100644
index 0000000000..242291c4f6
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseNamingConventionStartup.cs
@@ -0,0 +1,21 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using JetBrains.Annotations;
+using JsonApiDotNetCore.Configuration;
+using Microsoft.EntityFrameworkCore;
+
+namespace OpenApiTests.NamingConventions.CamelCase;
+
+[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
+public sealed class CamelCaseNamingConventionStartup : OpenApiStartup
+ where TDbContext : DbContext
+{
+ protected override void SetJsonApiOptions(JsonApiOptions options)
+ {
+ base.SetJsonApiOptions(options);
+
+ options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ options.SerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
+ options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
+ }
+}
diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs
new file mode 100644
index 0000000000..e0bbd5bad3
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs
@@ -0,0 +1,550 @@
+using System.Text.Json;
+using TestBuildingBlocks;
+using Xunit;
+
+namespace OpenApiTests.NamingConventions.CamelCase;
+
+public sealed class CamelCaseTests : IClassFixture, NamingConventionsDbContext>>
+{
+ private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext;
+
+ public CamelCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext)
+ {
+ _testContext = testContext;
+
+ testContext.UseController();
+ testContext.SwaggerDocumentOutputPath = "test/OpenApiClientTests/NamingConventions/CamelCase";
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetCollection_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarketCollection");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarketCollectionResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceCollectionDocumentSchemaRefId = null;
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeSchemaReferenceId("jsonapiObject");
+
+ linksInResourceCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("linksInResourceCollectionDocument").SchemaReferenceId;
+
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeSchemaReferenceId("supermarketDataInResponse")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceCollectionDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("first");
+ propertiesElement.Should().ContainProperty("last");
+ propertiesElement.Should().ContainProperty("prev");
+ propertiesElement.Should().ContainProperty("next");
+ });
+
+ string? linksInResourceObjectSchemaRefId = null;
+ string? primaryResourceTypeSchemaRefId = null;
+ string? resourceAttributesInResponseSchemaRefId = null;
+ string? resourceRelationshipInResponseSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInResourceObject")
+ .SchemaReferenceId;
+
+ primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("supermarketResourceType")
+ .SchemaReferenceId;
+
+ resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref")
+ .ShouldBeSchemaReferenceId("supermarketAttributesInResponse").SchemaReferenceId;
+
+ resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref")
+ .ShouldBeSchemaReferenceId("supermarketRelationshipsInResponse").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceObjectSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ });
+
+ schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement =>
+ {
+ enumValueElement.ShouldBeString("supermarkets");
+ });
+
+ schemasElement.ShouldContainPath($"{resourceAttributesInResponseSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("nameOfCity");
+ propertiesElement.Should().ContainProperty("kind");
+ propertiesElement.ShouldContainPath("kind.$ref").ShouldBeSchemaReferenceId("supermarketType");
+ });
+
+ string? nullableToOneResourceResponseDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceRelationshipInResponseSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("storeManager");
+
+ propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeSchemaReferenceId("toOneStaffMemberInResponse");
+
+ nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backupStoreManager.$ref")
+ .ShouldBeSchemaReferenceId("nullableToOneStaffMemberInResponse").SchemaReferenceId;
+
+ propertiesElement.Should().ContainProperty("cashiers");
+ propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("toManyStaffMemberInResponse");
+ });
+
+ string? linksInRelationshipObjectSchemaRefId = null;
+ string? relatedResourceIdentifierSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInRelationshipObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInRelationshipObject")
+ .SchemaReferenceId;
+
+ relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref")
+ .ShouldBeSchemaReferenceId("staffMemberIdentifier").SchemaReferenceId;
+
+ propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeSchemaReferenceId("nullValue");
+ });
+
+ schemasElement.ShouldContainPath($"{linksInRelationshipObjectSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("related");
+ });
+
+ string? relatedResourceTypeSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement =>
+ {
+ relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("staffMemberResourceType")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeSchemaReferenceId("staffMembers");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSingle_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarketPrimaryResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInResourceDocument")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}/storeManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarketStoreManager");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staffMemberSecondaryResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("staffMemberDataInResponse")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("staffMemberAttributesInResponse");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarketBackupStoreManager");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("nullableStaffMemberSecondaryResponseDocument");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarketCashiers");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staffMemberCollectionResponseDocument");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarketStoreManagerRelationship");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staffMemberIdentifierResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceIdentifierDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceIdentifierDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("linksInResourceIdentifierDocument").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceIdentifierDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("related");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarketBackupStoreManagerRelationship");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("nullableStaffMemberIdentifierResponseDocument");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("getSupermarketCashiersRelationship");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staffMemberIdentifierCollectionResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceIdentifierCollectionDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceIdentifierCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("linksInResourceIdentifierCollectionDocument").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceIdentifierCollectionDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("related");
+ propertiesElement.Should().ContainProperty("first");
+ propertiesElement.Should().ContainProperty("last");
+ propertiesElement.Should().ContainProperty("prev");
+ propertiesElement.Should().ContainProperty("next");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Post_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets.post").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("postSupermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarketPostRequestDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarketDataInPostRequest")
+ .SchemaReferenceId;
+ });
+
+ string? resourceRelationshipInPostRequestSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarketAttributesInPostRequest");
+
+ resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref")
+ .ShouldBeSchemaReferenceId("supermarketRelationshipsInPostRequest").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("storeManager");
+ propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeSchemaReferenceId("toOneStaffMemberInRequest");
+
+ propertiesElement.Should().ContainProperty("backupStoreManager");
+ propertiesElement.ShouldContainPath("backupStoreManager.$ref").ShouldBeSchemaReferenceId("nullableToOneStaffMemberInRequest");
+
+ propertiesElement.Should().ContainProperty("cashiers");
+ propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("toManyStaffMemberInRequest");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("postSupermarketCashiersRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Patch_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patchSupermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarketPatchRequestDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarketDataInPatchRequest")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarketAttributesInPatchRequest");
+ propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeSchemaReferenceId("supermarketRelationshipsInPatchRequest");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patchSupermarketStoreManagerRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patchSupermarketBackupStoreManagerRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patchSupermarketCashiersRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Delete_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("deleteSupermarket");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("deleteSupermarketCashiersRelationship");
+ });
+ });
+ }
+}
diff --git a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseNamingConventionStartup.cs
new file mode 100644
index 0000000000..ebd532aa65
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseNamingConventionStartup.cs
@@ -0,0 +1,21 @@
+using System.Text.Json.Serialization;
+using JetBrains.Annotations;
+using JsonApiDotNetCore.Configuration;
+using Microsoft.EntityFrameworkCore;
+using OpenApiTests.LegacyOpenApiIntegration;
+
+namespace OpenApiTests.NamingConventions.KebabCase;
+
+[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
+public sealed class KebabCaseNamingConventionStartup : OpenApiStartup
+ where TDbContext : DbContext
+{
+ protected override void SetJsonApiOptions(JsonApiOptions options)
+ {
+ base.SetJsonApiOptions(options);
+
+ options.SerializerOptions.PropertyNamingPolicy = JsonKebabCaseNamingPolicy.Instance;
+ options.SerializerOptions.DictionaryKeyPolicy = JsonKebabCaseNamingPolicy.Instance;
+ options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
+ }
+}
diff --git a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs
new file mode 100644
index 0000000000..0a532a6e3f
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs
@@ -0,0 +1,550 @@
+using System.Text.Json;
+using TestBuildingBlocks;
+using Xunit;
+
+namespace OpenApiTests.NamingConventions.KebabCase;
+
+public sealed class KebabCaseTests : IClassFixture, NamingConventionsDbContext>>
+{
+ private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext;
+
+ public KebabCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext)
+ {
+ _testContext = testContext;
+
+ testContext.UseController();
+ testContext.SwaggerDocumentOutputPath = "test/OpenApiClientTests/NamingConventions/KebabCase";
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetCollection_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket-collection");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarket-collection-response-document").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceCollectionDocumentSchemaRefId = null;
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeSchemaReferenceId("jsonapi-object");
+
+ linksInResourceCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("links-in-resource-collection-document").SchemaReferenceId;
+
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeSchemaReferenceId("supermarket-data-in-response")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceCollectionDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("first");
+ propertiesElement.Should().ContainProperty("last");
+ propertiesElement.Should().ContainProperty("prev");
+ propertiesElement.Should().ContainProperty("next");
+ });
+
+ string? linksInResourceObjectSchemaRefId = null;
+ string? primaryResourceTypeSchemaRefId = null;
+ string? resourceAttributesInResponseSchemaRefId = null;
+ string? resourceRelationshipInResponseSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("links-in-resource-object")
+ .SchemaReferenceId;
+
+ primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("supermarket-resource-type")
+ .SchemaReferenceId;
+
+ resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref")
+ .ShouldBeSchemaReferenceId("supermarket-attributes-in-response").SchemaReferenceId;
+
+ resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref")
+ .ShouldBeSchemaReferenceId("supermarket-relationships-in-response").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceObjectSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ });
+
+ schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement =>
+ {
+ enumValueElement.ShouldBeString("supermarkets");
+ });
+
+ schemasElement.ShouldContainPath($"{resourceAttributesInResponseSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("name-of-city");
+ propertiesElement.Should().ContainProperty("kind");
+ propertiesElement.ShouldContainPath("kind.$ref").ShouldBeSchemaReferenceId("supermarket-type");
+ });
+
+ string? nullableToOneResourceResponseDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceRelationshipInResponseSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("store-manager");
+
+ propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeSchemaReferenceId("to-one-staff-member-in-response");
+
+ nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backup-store-manager.$ref")
+ .ShouldBeSchemaReferenceId("nullable-to-one-staff-member-in-response").SchemaReferenceId;
+
+ propertiesElement.Should().ContainProperty("cashiers");
+ propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("to-many-staff-member-in-response");
+ });
+
+ string? linksInRelationshipObjectSchemaRefId = null;
+ string? relatedResourceIdentifierSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInRelationshipObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("links-in-relationship-object").SchemaReferenceId;
+
+ relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref")
+ .ShouldBeSchemaReferenceId("staff-member-identifier").SchemaReferenceId;
+
+ propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeSchemaReferenceId("null-value");
+ });
+
+ schemasElement.ShouldContainPath($"{linksInRelationshipObjectSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("related");
+ });
+
+ string? relatedResourceTypeSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement =>
+ {
+ relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("staff-member-resource-type")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeSchemaReferenceId("staff-members");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSingle_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarket-primary-response-document").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("links-in-resource-document")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}/store-manager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket-store-manager");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staff-member-secondary-response-document").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("staff-member-data-in-response")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("staff-member-attributes-in-response");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket-backup-store-manager");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("nullable-staff-member-secondary-response-document");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket-cashiers");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staff-member-collection-response-document");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket-store-manager-relationship");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staff-member-identifier-response-document").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceIdentifierDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceIdentifierDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("links-in-resource-identifier-document").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceIdentifierDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("related");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket-backup-store-manager-relationship");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("nullable-staff-member-identifier-response-document");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("get-supermarket-cashiers-relationship");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("staff-member-identifier-collection-response-document").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceIdentifierCollectionDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceIdentifierCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("links-in-resource-identifier-collection-document").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceIdentifierCollectionDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("related");
+ propertiesElement.Should().ContainProperty("first");
+ propertiesElement.Should().ContainProperty("last");
+ propertiesElement.Should().ContainProperty("prev");
+ propertiesElement.Should().ContainProperty("next");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Post_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets.post").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("post-supermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarket-post-request-document").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarket-data-in-post-request")
+ .SchemaReferenceId;
+ });
+
+ string? resourceRelationshipInPostRequestSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarket-attributes-in-post-request");
+
+ resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref")
+ .ShouldBeSchemaReferenceId("supermarket-relationships-in-post-request").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("store-manager");
+ propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeSchemaReferenceId("to-one-staff-member-in-request");
+
+ propertiesElement.Should().ContainProperty("backup-store-manager");
+ propertiesElement.ShouldContainPath("backup-store-manager.$ref").ShouldBeSchemaReferenceId("nullable-to-one-staff-member-in-request");
+
+ propertiesElement.Should().ContainProperty("cashiers");
+ propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("to-many-staff-member-in-request");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("post-supermarket-cashiers-relationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Patch_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patch-supermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("supermarket-patch-request-document").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarket-data-in-patch-request")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarket-attributes-in-patch-request");
+ propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeSchemaReferenceId("supermarket-relationships-in-patch-request");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patch-supermarket-store-manager-relationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patch-supermarket-backup-store-manager-relationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("patch-supermarket-cashiers-relationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Delete_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("delete-supermarket");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("delete-supermarket-cashiers-relationship");
+ });
+ });
+ }
+}
diff --git a/test/OpenApiTests/NamingConventions/NamingConventionsDbContext.cs b/test/OpenApiTests/NamingConventions/NamingConventionsDbContext.cs
new file mode 100644
index 0000000000..eb2d0b52d2
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/NamingConventionsDbContext.cs
@@ -0,0 +1,15 @@
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore;
+
+namespace OpenApiTests.NamingConventions;
+
+[UsedImplicitly(ImplicitUseTargetFlags.Members)]
+public sealed class NamingConventionsDbContext : DbContext
+{
+ public DbSet Supermarkets => Set();
+
+ public NamingConventionsDbContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+}
diff --git a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseNamingConventionStartup.cs
new file mode 100644
index 0000000000..7c934b94e4
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseNamingConventionStartup.cs
@@ -0,0 +1,20 @@
+using System.Text.Json.Serialization;
+using JetBrains.Annotations;
+using JsonApiDotNetCore.Configuration;
+using Microsoft.EntityFrameworkCore;
+
+namespace OpenApiTests.NamingConventions.PascalCase;
+
+[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
+public sealed class PascalCaseNamingConventionStartup : OpenApiStartup
+ where TDbContext : DbContext
+{
+ protected override void SetJsonApiOptions(JsonApiOptions options)
+ {
+ base.SetJsonApiOptions(options);
+
+ options.SerializerOptions.PropertyNamingPolicy = null;
+ options.SerializerOptions.DictionaryKeyPolicy = null;
+ options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
+ }
+}
diff --git a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs
new file mode 100644
index 0000000000..73868dcdad
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs
@@ -0,0 +1,551 @@
+using System.Text.Json;
+using TestBuildingBlocks;
+using Xunit;
+
+namespace OpenApiTests.NamingConventions.PascalCase;
+
+public sealed class PascalCaseTests
+ : IClassFixture, NamingConventionsDbContext>>
+{
+ private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext;
+
+ public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext)
+ {
+ _testContext = testContext;
+
+ testContext.UseController();
+ testContext.SwaggerDocumentOutputPath = "test/OpenApiClientTests/NamingConventions/PascalCase";
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetCollection_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./Supermarkets.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarketCollection");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("SupermarketCollectionResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceCollectionDocumentSchemaRefId = null;
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeSchemaReferenceId("JsonapiObject");
+
+ linksInResourceCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("LinksInResourceCollectionDocument").SchemaReferenceId;
+
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeSchemaReferenceId("SupermarketDataInResponse")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceCollectionDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("first");
+ propertiesElement.Should().ContainProperty("last");
+ propertiesElement.Should().ContainProperty("prev");
+ propertiesElement.Should().ContainProperty("next");
+ });
+
+ string? linksInResourceObjectSchemaRefId = null;
+ string? primaryResourceTypeSchemaRefId = null;
+ string? resourceAttributesInResponseSchemaRefId = null;
+ string? resourceRelationshipInResponseSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("LinksInResourceObject")
+ .SchemaReferenceId;
+
+ primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("SupermarketResourceType")
+ .SchemaReferenceId;
+
+ resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref")
+ .ShouldBeSchemaReferenceId("SupermarketAttributesInResponse").SchemaReferenceId;
+
+ resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref")
+ .ShouldBeSchemaReferenceId("SupermarketRelationshipsInResponse").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceObjectSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ });
+
+ schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement =>
+ {
+ enumValueElement.ShouldBeString("Supermarkets");
+ });
+
+ schemasElement.ShouldContainPath($"{resourceAttributesInResponseSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("NameOfCity");
+ propertiesElement.Should().ContainProperty("Kind");
+ propertiesElement.ShouldContainPath("Kind.$ref").ShouldBeSchemaReferenceId("SupermarketType");
+ });
+
+ string? nullableToOneResourceResponseDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceRelationshipInResponseSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("StoreManager");
+
+ propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeSchemaReferenceId("ToOneStaffMemberInResponse");
+
+ nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("BackupStoreManager.$ref")
+ .ShouldBeSchemaReferenceId("NullableToOneStaffMemberInResponse").SchemaReferenceId;
+
+ propertiesElement.Should().ContainProperty("Cashiers");
+ propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeSchemaReferenceId("ToManyStaffMemberInResponse");
+ });
+
+ string? linksInRelationshipObjectSchemaRefId = null;
+ string? relatedResourceIdentifierSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInRelationshipObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("LinksInRelationshipObject")
+ .SchemaReferenceId;
+
+ relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref")
+ .ShouldBeSchemaReferenceId("StaffMemberIdentifier").SchemaReferenceId;
+
+ propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeSchemaReferenceId("NullValue");
+ });
+
+ schemasElement.ShouldContainPath($"{linksInRelationshipObjectSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("related");
+ });
+
+ string? relatedResourceTypeSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement =>
+ {
+ relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("StaffMemberResourceType")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeSchemaReferenceId("StaffMembers");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSingle_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./Supermarkets/{id}.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("SupermarketPrimaryResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("LinksInResourceDocument")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./Supermarkets/{id}/StoreManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarketStoreManager");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("StaffMemberSecondaryResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("StaffMemberDataInResponse")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("StaffMemberAttributesInResponse");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarketBackupStoreManager");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("NullableStaffMemberSecondaryResponseDocument");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarketCashiers");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("StaffMemberCollectionResponseDocument");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarketStoreManagerRelationship");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("StaffMemberIdentifierResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceIdentifierDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceIdentifierDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("LinksInResourceIdentifierDocument").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceIdentifierDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("related");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarketBackupStoreManagerRelationship");
+ });
+
+ getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("NullableStaffMemberIdentifierResponseDocument");
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.get").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("GetSupermarketCashiersRelationship");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("StaffMemberIdentifierCollectionResponseDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? linksInResourceIdentifierCollectionDocumentSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ linksInResourceIdentifierCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref")
+ .ShouldBeSchemaReferenceId("LinksInResourceIdentifierCollectionDocument").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{linksInResourceIdentifierCollectionDocumentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("self");
+ propertiesElement.Should().ContainProperty("describedby");
+ propertiesElement.Should().ContainProperty("related");
+ propertiesElement.Should().ContainProperty("first");
+ propertiesElement.Should().ContainProperty("last");
+ propertiesElement.Should().ContainProperty("prev");
+ propertiesElement.Should().ContainProperty("next");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Post_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./Supermarkets.post").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("PostSupermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("SupermarketPostRequestDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("SupermarketDataInPostRequest")
+ .SchemaReferenceId;
+ });
+
+ string? resourceRelationshipInPostRequestSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("SupermarketAttributesInPostRequest");
+
+ resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref")
+ .ShouldBeSchemaReferenceId("SupermarketRelationshipsInPostRequest").SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.Should().ContainProperty("StoreManager");
+ propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeSchemaReferenceId("ToOneStaffMemberInRequest");
+
+ propertiesElement.Should().ContainProperty("BackupStoreManager");
+ propertiesElement.ShouldContainPath("BackupStoreManager.$ref").ShouldBeSchemaReferenceId("NullableToOneStaffMemberInRequest");
+
+ propertiesElement.Should().ContainProperty("Cashiers");
+ propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeSchemaReferenceId("ToManyStaffMemberInRequest");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("PostSupermarketCashiersRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Patch_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ string? documentSchemaRefId = null;
+
+ document.ShouldContainPath("paths./Supermarkets/{id}.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("PatchSupermarket");
+ });
+
+ documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref")
+ .ShouldBeSchemaReferenceId("SupermarketPatchRequestDocument").SchemaReferenceId;
+ });
+
+ document.ShouldContainPath("components.schemas").With(schemasElement =>
+ {
+ string? resourceDataSchemaRefId = null;
+
+ schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement =>
+ {
+ resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("SupermarketDataInPatchRequest")
+ .SchemaReferenceId;
+ });
+
+ schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement =>
+ {
+ propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("SupermarketAttributesInPatchRequest");
+ propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeSchemaReferenceId("SupermarketRelationshipsInPatchRequest");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("PatchSupermarketStoreManagerRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("PatchSupermarketBackupStoreManagerRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("PatchSupermarketCashiersRelationship");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_Delete_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("DeleteSupermarket");
+ });
+ });
+ }
+
+ [Fact]
+ public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint()
+ {
+ // Act
+ JsonElement document = await _testContext.GetSwaggerDocumentAsync();
+
+ // Assert
+ document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement =>
+ {
+ getElement.ShouldContainPath("operationId").With(operationElement =>
+ {
+ operationElement.ShouldBeString("DeleteSupermarketCashiersRelationship");
+ });
+ });
+ }
+}
diff --git a/test/OpenApiTests/NamingConventions/StaffMember.cs b/test/OpenApiTests/NamingConventions/StaffMember.cs
new file mode 100644
index 0000000000..d14c30a422
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/StaffMember.cs
@@ -0,0 +1,15 @@
+using JetBrains.Annotations;
+using JsonApiDotNetCore.Resources;
+using JsonApiDotNetCore.Resources.Annotations;
+
+namespace OpenApiTests.NamingConventions;
+
+[UsedImplicitly(ImplicitUseTargetFlags.Members)]
+public sealed class StaffMember : Identifiable
+{
+ [Attr]
+ public string Name { get; set; } = null!;
+
+ [Attr]
+ public int Age { get; set; }
+}
diff --git a/test/OpenApiTests/NamingConventions/Supermarket.cs b/test/OpenApiTests/NamingConventions/Supermarket.cs
new file mode 100644
index 0000000000..4bde8776da
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/Supermarket.cs
@@ -0,0 +1,25 @@
+using JetBrains.Annotations;
+using JsonApiDotNetCore.Resources;
+using JsonApiDotNetCore.Resources.Annotations;
+
+namespace OpenApiTests.NamingConventions;
+
+[UsedImplicitly(ImplicitUseTargetFlags.Members)]
+[Resource(ControllerNamespace = "OpenApiTests.NamingConventions")]
+public sealed class Supermarket : Identifiable
+{
+ [Attr]
+ public string NameOfCity { get; set; } = null!;
+
+ [Attr]
+ public SupermarketType Kind { get; set; }
+
+ [HasOne]
+ public StaffMember StoreManager { get; set; } = null!;
+
+ [HasOne]
+ public StaffMember? BackupStoreManager { get; set; }
+
+ [HasMany]
+ public ICollection Cashiers { get; set; } = new HashSet();
+}
diff --git a/test/OpenApiTests/NamingConventions/SupermarketType.cs b/test/OpenApiTests/NamingConventions/SupermarketType.cs
new file mode 100644
index 0000000000..45570936f5
--- /dev/null
+++ b/test/OpenApiTests/NamingConventions/SupermarketType.cs
@@ -0,0 +1,11 @@
+using JetBrains.Annotations;
+
+namespace OpenApiTests.NamingConventions;
+
+[UsedImplicitly(ImplicitUseTargetFlags.Members)]
+public enum SupermarketType
+{
+ Traditional,
+ Budget,
+ Warehouse
+}
diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs
new file mode 100644
index 0000000000..a750929827
--- /dev/null
+++ b/test/OpenApiTests/OpenApiTestContext.cs
@@ -0,0 +1,80 @@
+using System.Reflection;
+using System.Text.Json;
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore;
+using TestBuildingBlocks;
+using SysNotNull = System.Diagnostics.CodeAnalysis.NotNullAttribute;
+
+namespace OpenApiTests;
+
+[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
+public class OpenApiTestContext : IntegrationTestContext
+ where TStartup : class
+ where TDbContext : DbContext
+{
+ private readonly Lazy> _lazySwaggerDocument;
+
+ internal string? SwaggerDocumentOutputPath { private get; set; }
+
+ public OpenApiTestContext()
+ {
+ _lazySwaggerDocument = new Lazy>(CreateSwaggerDocumentAsync, LazyThreadSafetyMode.ExecutionAndPublication);
+ }
+
+ internal async Task GetSwaggerDocumentAsync()
+ {
+ return await _lazySwaggerDocument.Value;
+ }
+
+ private async Task CreateSwaggerDocumentAsync()
+ {
+ string absoluteOutputPath = GetSwaggerDocumentAbsoluteOutputPath(SwaggerDocumentOutputPath);
+
+ string content = await GetAsync("swagger/v1/swagger.json");
+
+ JsonElement rootElement = ParseSwaggerDocument(content);
+ await WriteToDiskAsync(absoluteOutputPath, rootElement);
+
+ return rootElement;
+ }
+
+ private static string GetSwaggerDocumentAbsoluteOutputPath(string? relativePath)
+ {
+ AssertHasSwaggerDocumentOutputPath(relativePath);
+
+ string solutionRoot = Path.Combine(Assembly.GetExecutingAssembly().Location, "../../../../../../");
+ string outputPath = Path.Combine(solutionRoot, relativePath, "swagger.g.json");
+
+ return Path.GetFullPath(outputPath);
+ }
+
+ private static void AssertHasSwaggerDocumentOutputPath([SysNotNull] string? relativePath)
+ {
+ if (relativePath is null)
+ {
+ throw new Exception($"Property '{nameof(OpenApiTestContext