Skip to content

Commit 3fe4e2e

Browse files
committed
closing down PR
1 parent ec2e678 commit 3fe4e2e

26 files changed

+2552
-167
lines changed

Directory.Build.props

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" PrivateAssets="All" />
15+
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" PrivateAssets="All" />
1616
<PackageReference Include="CSharpGuidelinesAnalyzer" Version="3.7.0" PrivateAssets="All" />
1717
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CSharpGuidelinesAnalyzer.config" Visible="False" />
1818
</ItemGroup>
1919

20-
<PropertyGroup Condition="'$(Configuration)'=='Release'">
21-
<NoWarn>$(NoWarn);1591</NoWarn>
22-
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
23-
<GenerateDocumentationFile>true</GenerateDocumentationFile>
24-
</PropertyGroup>
20+
<PropertyGroup Condition="'$(Configuration)'=='Release'">
21+
<NoWarn>$(NoWarn);1591</NoWarn>
22+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
23+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
24+
</PropertyGroup>
2525

2626
<!-- Test Project Dependencies -->
2727
<PropertyGroup>
@@ -31,5 +31,6 @@
3131
<MoqVersion>4.16.1</MoqVersion>
3232
<XUnitVersion>2.4.*</XUnitVersion>
3333
<TestSdkVersion>17.0.0</TestSdkVersion>
34+
<BlushingPenguinVersion>1.0.*</BlushingPenguinVersion>
3435
</PropertyGroup>
3536
</Project>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using JetBrains.Annotations;
4+
5+
// ReSharper disable once CheckNamespace
6+
namespace JsonApiDotNetCore.OpenApi.Client.Exceptions
7+
{
8+
// We cannot rely on a generated ApiException as soon as we are generating multiple clients, see https://github.com/RicoSuter/NSwag/issues/2839#issuecomment-776647377.
9+
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
10+
internal class ApiException : Exception
11+
{
12+
public int StatusCode { get; }
13+
14+
public string Response { get; }
15+
16+
public IReadOnlyDictionary<string, IEnumerable<string>> Headers { get; }
17+
18+
public ApiException(string message, int statusCode, string response, IReadOnlyDictionary<string, IEnumerable<string>> headers, Exception innerException)
19+
: base(
20+
message + "\n\nStatus: " + statusCode + "\nResponse: \n" +
21+
(response == null ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException)
22+
{
23+
StatusCode = statusCode;
24+
Response = response;
25+
Headers = headers;
26+
}
27+
28+
public override string ToString()
29+
{
30+
return $"HTTP Response: \n\n{Response}\n\n{base.ToString()}";
31+
}
32+
}
33+
34+
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
35+
internal sealed class ApiException<TResult> : ApiException
36+
{
37+
public TResult Result { get; }
38+
39+
public ApiException(string message, int statusCode, string response, IReadOnlyDictionary<string, IEnumerable<string>> headers, TResult result,
40+
Exception innerException)
41+
: base(message, statusCode, response, headers, innerException)
42+
{
43+
Result = result;
44+
}
45+
}
46+
}
Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Text.Json;
45
using Humanizer;
56
using JsonApiDotNetCore.Configuration;
67
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
@@ -13,42 +14,41 @@ internal sealed class JsonApiSchemaIdSelector
1314
{
1415
private static readonly IDictionary<Type, string> OpenTypeToSchemaTemplateMap = new Dictionary<Type, string>
1516
{
16-
[typeof(ResourcePostRequestDocument<>)] = "###-post-request-document",
17-
[typeof(ResourcePatchRequestDocument<>)] = "###-patch-request-document",
18-
[typeof(ResourceObjectInPostRequest<>)] = "###-data-in-post-request",
19-
[typeof(AttributesInPostRequest<>)] = "###-attributes-in-post-request",
20-
[typeof(RelationshipsInPostRequest<>)] = "###-relationships-in-post-request",
21-
[typeof(ResourceObjectInPatchRequest<>)] = "###-data-in-patch-request",
22-
[typeof(AttributesInPatchRequest<>)] = "###-attributes-in-patch-request",
23-
[typeof(RelationshipsInPatchRequest<>)] = "###-relationships-in-patch-request",
24-
[typeof(ToOneRelationshipInRequest<>)] = "to-one-###-in-request",
25-
[typeof(NullableToOneRelationshipInRequest<>)] = "nullable-to-one-###-in-request",
26-
[typeof(ToManyRelationshipInRequest<>)] = "to-many-###-in-request",
27-
[typeof(PrimaryResourceResponseDocument<>)] = "###-primary-response-document",
28-
[typeof(SecondaryResourceResponseDocument<>)] = "###-secondary-response-document",
29-
[typeof(NullableSecondaryResourceResponseDocument<>)] = "nullable-###-secondary-response-document",
30-
[typeof(ResourceCollectionResponseDocument<>)] = "###-collection-response-document",
31-
[typeof(ResourceIdentifierResponseDocument<>)] = "###-identifier-response-document",
32-
[typeof(NullableResourceIdentifierResponseDocument<>)] = "nullable-###-identifier-response-document",
33-
[typeof(ResourceIdentifierCollectionResponseDocument<>)] = "###-identifier-collection-response-document",
34-
[typeof(ToOneRelationshipInResponse<>)] = "to-one-###-in-response",
35-
[typeof(NullableToOneRelationshipInResponse<>)] = "nullable-to-one-###-in-response",
36-
[typeof(ToManyRelationshipInResponse<>)] = "to-many-###-in-response",
37-
[typeof(ResourceObjectInResponse<>)] = "###-data-in-response",
38-
[typeof(AttributesInResponse<>)] = "###-attributes-in-response",
39-
[typeof(RelationshipsInResponse<>)] = "###-relationships-in-response",
40-
[typeof(ResourceIdentifierObject<>)] = "###-identifier"
17+
[typeof(ResourcePostRequestDocument<>)] = "[ResourceName] Post Request Document",
18+
[typeof(ResourcePatchRequestDocument<>)] = "[ResourceName] Patch Request Document",
19+
[typeof(ResourceObjectInPostRequest<>)] = "[ResourceName] Data In Post Request",
20+
[typeof(AttributesInPostRequest<>)] = "[ResourceName] Attributes In Post Request",
21+
[typeof(RelationshipsInPostRequest<>)] = "[ResourceName] Relationships In Post Request",
22+
[typeof(ResourceObjectInPatchRequest<>)] = "[ResourceName] Data In Patch Request",
23+
[typeof(AttributesInPatchRequest<>)] = "[ResourceName] Attributes In Patch Request",
24+
[typeof(RelationshipsInPatchRequest<>)] = "[ResourceName] Relationships In Patch Request",
25+
[typeof(ToOneRelationshipInRequest<>)] = "To One [ResourceName] In Request",
26+
[typeof(NullableToOneRelationshipInRequest<>)] = "Nullable To One [ResourceName] In Request",
27+
[typeof(ToManyRelationshipInRequest<>)] = "To Many [ResourceName] In Request",
28+
[typeof(PrimaryResourceResponseDocument<>)] = "[ResourceName] Primary Response Document",
29+
[typeof(SecondaryResourceResponseDocument<>)] = "[ResourceName] Secondary Response Document",
30+
[typeof(NullableSecondaryResourceResponseDocument<>)] = "Nullable [ResourceName] Secondary Response Document",
31+
[typeof(ResourceCollectionResponseDocument<>)] = "[ResourceName] Collection Response Document",
32+
[typeof(ResourceIdentifierResponseDocument<>)] = "[ResourceName] Identifier Response Document",
33+
[typeof(NullableResourceIdentifierResponseDocument<>)] = "Nullable [ResourceName] Identifier Response Document",
34+
[typeof(ResourceIdentifierCollectionResponseDocument<>)] = "[ResourceName] Identifier Collection Response Document",
35+
[typeof(ToOneRelationshipInResponse<>)] = "To One [ResourceName] In Response",
36+
[typeof(NullableToOneRelationshipInResponse<>)] = "Nullable To One [ResourceName] In Response",
37+
[typeof(ToManyRelationshipInResponse<>)] = "To Many [ResourceName] In Response",
38+
[typeof(ResourceObjectInResponse<>)] = "[ResourceName] Data In Response",
39+
[typeof(AttributesInResponse<>)] = "[ResourceName] Attributes In Response",
40+
[typeof(RelationshipsInResponse<>)] = "[ResourceName] Relationships In Response",
41+
[typeof(ResourceIdentifierObject<>)] = "[ResourceName] Identifier"
4142
};
4243

43-
private readonly ResourceNameFormatter _formatter;
44+
private readonly JsonNamingPolicy? _namingPolicy;
4445
private readonly IResourceGraph _resourceGraph;
4546

46-
public JsonApiSchemaIdSelector(ResourceNameFormatter formatter, IResourceGraph resourceGraph)
47+
public JsonApiSchemaIdSelector(JsonNamingPolicy? namingPolicy, IResourceGraph resourceGraph)
4748
{
48-
ArgumentGuard.NotNull(formatter, nameof(formatter));
4949
ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph));
5050

51-
_formatter = formatter;
51+
_namingPolicy = namingPolicy;
5252
_resourceGraph = resourceGraph;
5353
}
5454

@@ -65,15 +65,24 @@ public string GetSchemaId(Type type)
6565

6666
if (type.IsConstructedGenericType && OpenTypeToSchemaTemplateMap.ContainsKey(type.GetGenericTypeDefinition()))
6767
{
68+
string pascalCaseSchemaIdTemplate = OpenTypeToSchemaTemplateMap[type.GetGenericTypeDefinition()];
6869
Type resourceClrType = type.GetGenericArguments().First();
69-
string resourceName = _formatter.FormatResourceName(resourceClrType).Singularize();
7070

71-
string template = OpenTypeToSchemaTemplateMap[type.GetGenericTypeDefinition()];
72-
return template.Replace("###", resourceName);
71+
// @formatter:wrap_chained_method_calls chop_always
72+
// @formatter:keep_existing_linebreaks true
73+
74+
string pascalCaseSchemaId = pascalCaseSchemaIdTemplate
75+
.Replace("[ResourceName]", resourceClrType.Name)
76+
.Replace(" ", "");
77+
78+
// @formatter:keep_existing_linebreaks restore
79+
// @formatter:wrap_chained_method_calls restore
80+
81+
return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId;
7382
}
7483

7584
// Used for a fixed set of types, such as jsonapi-object, links-in-many-resource-document etc.
76-
return _formatter.FormatResourceName(type).Singularize();
85+
return _namingPolicy != null ? _namingPolicy.ConvertName(type.Name) : type.Name;
7786
}
7887
}
7988
}

src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,14 @@ private static void AddSwaggerGenerator(IServiceScope scope, IServiceCollection
5959
var resourceGraph = scope.ServiceProvider.GetRequiredService<IResourceGraph>();
6060
var jsonApiOptions = scope.ServiceProvider.GetRequiredService<IJsonApiOptions>();
6161
JsonNamingPolicy? namingPolicy = jsonApiOptions.SerializerOptions.PropertyNamingPolicy;
62-
ResourceNameFormatter resourceNameFormatter = new(namingPolicy);
6362

6463
AddSchemaGenerator(services);
6564

6665
services.AddSwaggerGen(swaggerGenOptions =>
6766
{
6867
swaggerGenOptions.SupportNonNullableReferenceTypes();
6968
SetOperationInfo(swaggerGenOptions, controllerResourceMapping, namingPolicy);
70-
SetSchemaIdSelector(swaggerGenOptions, resourceGraph, resourceNameFormatter);
69+
SetSchemaIdSelector(swaggerGenOptions, resourceGraph, namingPolicy);
7170
swaggerGenOptions.DocumentFilter<EndpointOrderingFilter>();
7271

7372
setupSwaggerGenAction?.Invoke(swaggerGenOptions);
@@ -105,9 +104,9 @@ private static IList<string> GetOperationTags(ApiDescription description, IContr
105104
};
106105
}
107106

108-
private static void SetSchemaIdSelector(SwaggerGenOptions swaggerGenOptions, IResourceGraph resourceGraph, ResourceNameFormatter resourceNameFormatter)
107+
private static void SetSchemaIdSelector(SwaggerGenOptions swaggerGenOptions, IResourceGraph resourceGraph, JsonNamingPolicy? namingPolicy)
109108
{
110-
JsonApiSchemaIdSelector jsonApiObjectSchemaSelector = new(resourceNameFormatter, resourceGraph);
109+
JsonApiSchemaIdSelector jsonApiObjectSchemaSelector = new(namingPolicy, resourceGraph);
111110

112111
swaggerGenOptions.CustomSchemaIds(type => jsonApiObjectSchemaSelector.GetSchemaId(type));
113112
}

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public JsonApiSchemaGenerator(SchemaGenerator defaultSchemaGenerator, IResourceG
4040
ArgumentGuard.NotNull(options, nameof(options));
4141

4242
_defaultSchemaGenerator = defaultSchemaGenerator;
43-
_nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(_schemaRepositoryAccessor);
43+
_nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(_schemaRepositoryAccessor, options.SerializerOptions.PropertyNamingPolicy);
4444
_resourceObjectSchemaGenerator = new ResourceObjectSchemaGenerator(defaultSchemaGenerator, resourceGraph, options, _schemaRepositoryAccessor);
4545
}
4646

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Text.Json;
34
using Microsoft.OpenApi.Models;
45

56
namespace JsonApiDotNetCore.OpenApi.SwaggerComponents
67
{
78
internal sealed class NullableReferenceSchemaGenerator
89
{
10+
private const string PascalCaseNullableSchemaReferenceId = "NullValue";
11+
private readonly string _nullableSchemaReferenceId;
12+
913
private static readonly NullableReferenceSchemaStrategy NullableReferenceStrategy =
1014
Enum.Parse<NullableReferenceSchemaStrategy>(NullableReferenceSchemaStrategy.Implicit.ToString());
1115

12-
private static OpenApiSchema? _referenceSchemaForNullValue;
16+
private static OpenApiSchema? _referenceSchemaForExplicitNullValue;
1317
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
1418

15-
public NullableReferenceSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor)
19+
public NullableReferenceSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor, JsonNamingPolicy? namingPolicy)
1620
{
1721
ArgumentGuard.NotNull(schemaRepositoryAccessor, nameof(schemaRepositoryAccessor));
1822

1923
_schemaRepositoryAccessor = schemaRepositoryAccessor;
24+
_nullableSchemaReferenceId = namingPolicy != null ? namingPolicy.ConvertName(PascalCaseNullableSchemaReferenceId) : PascalCaseNullableSchemaReferenceId;
2025
}
2126

2227
public OpenApiSchema GenerateSchema(OpenApiSchema referenceSchema)
@@ -28,20 +33,13 @@ public OpenApiSchema GenerateSchema(OpenApiSchema referenceSchema)
2833
OneOf = new List<OpenApiSchema>
2934
{
3035
referenceSchema,
31-
GetNullableReferenceSchema()
36+
NullableReferenceStrategy == NullableReferenceSchemaStrategy.Explicit ? GetExplicitNullSchema() : GetImplicitNullSchema()
3237
}
3338
};
3439
}
3540

36-
private OpenApiSchema GetNullableReferenceSchema()
37-
{
38-
return NullableReferenceStrategy == NullableReferenceSchemaStrategy.Explicit
39-
? GetNullableReferenceSchemaUsingExplicitNullType()
40-
: GetNullableReferenceSchemaUsingImplicitNullType();
41-
}
42-
4341
// This approach is supported in OAS starting from v3.1. See https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-580103688
44-
private static OpenApiSchema GetNullableReferenceSchemaUsingExplicitNullType()
42+
private static OpenApiSchema GetExplicitNullSchema()
4543
{
4644
return new OpenApiSchema
4745
{
@@ -50,48 +48,58 @@ private static OpenApiSchema GetNullableReferenceSchemaUsingExplicitNullType()
5048
}
5149

5250
// This approach is supported starting from OAS v3.0. See https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-487314681
53-
private OpenApiSchema GetNullableReferenceSchemaUsingImplicitNullType()
51+
private OpenApiSchema GetImplicitNullSchema()
5452
{
55-
if (_referenceSchemaForNullValue != null)
53+
EnsureFullSchemaForNullValueExists();
54+
55+
return _referenceSchemaForExplicitNullValue ??= new OpenApiSchema
5656
{
57-
return _referenceSchemaForNullValue;
58-
}
57+
Reference = new OpenApiReference
58+
{
59+
Id = _nullableSchemaReferenceId,
60+
Type = ReferenceType.Schema
61+
}
62+
};
63+
}
5964

60-
var fullSchemaForNullValue = new OpenApiSchema
65+
private void EnsureFullSchemaForNullValueExists()
66+
{
67+
if (!_schemaRepositoryAccessor.Current.Schemas.ContainsKey(_nullableSchemaReferenceId))
6168
{
62-
Nullable = true,
63-
Not = new OpenApiSchema
69+
var fullSchemaForNullValue = new OpenApiSchema
6470
{
65-
AnyOf = new List<OpenApiSchema>
71+
Nullable = true,
72+
Not = new OpenApiSchema
6673
{
67-
new()
74+
AnyOf = new List<OpenApiSchema>
6875
{
69-
Type = "string"
76+
new()
77+
{
78+
Type = "string"
79+
},
80+
new()
81+
{
82+
Type = "number"
83+
},
84+
new()
85+
{
86+
Type = "boolean"
87+
},
88+
new()
89+
{
90+
Type = "object"
91+
},
92+
new()
93+
{
94+
Type = "array"
95+
}
7096
},
71-
new()
72-
{
73-
Type = "number"
74-
},
75-
new()
76-
{
77-
Type = "boolean"
78-
},
79-
new()
80-
{
81-
Type = "object"
82-
},
83-
new()
84-
{
85-
Type = "array"
86-
}
87-
},
88-
Items = new OpenApiSchema()
89-
}
90-
};
97+
Items = new OpenApiSchema()
98+
}
99+
};
91100

92-
_referenceSchemaForNullValue = _schemaRepositoryAccessor.Current.AddDefinition("null-value", fullSchemaForNullValue);
93-
94-
return _referenceSchemaForNullValue;
101+
_schemaRepositoryAccessor.Current.AddDefinition(_nullableSchemaReferenceId, fullSchemaForNullValue);
102+
}
95103
}
96104
}
97105
}

0 commit comments

Comments
 (0)