Skip to content

Commit 64d1503

Browse files
committed
Extract resource identifier schema generator
1 parent 5c53abb commit 64d1503

7 files changed

+75
-53
lines changed

src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ private static void SetSchemaIdSelector(SwaggerGenOptions swaggerGenOptions, IRe
118118
private static void AddCustomSwaggerComponents(IServiceCollection services)
119119
{
120120
services.TryAddSingleton<SwaggerGenerator>();
121-
services.TryAddSingleton<ISwaggerProvider, CachingSwaggerGenerator>();
121+
services.TryAddSingleton<ISwaggerProvider, CachingSwaggerProvider>();
122122

123123
services.TryAddSingleton<ISerializerDataContractResolver, JsonApiDataContractResolver>();
124124
}

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/CachingSwaggerGenerator.cs renamed to src/JsonApiDotNetCore.OpenApi/SwaggerComponents/CachingSwaggerProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ namespace JsonApiDotNetCore.OpenApi.SwaggerComponents;
99
/// The default <see cref="ISwaggerProvider" /> implementation re-renders the OpenApiDocument every time it is requested, which is redundant in our case.
1010
/// This implementation provides a very basic caching layer.
1111
/// </summary>
12-
internal sealed class CachingSwaggerGenerator : ISwaggerProvider
12+
internal sealed class CachingSwaggerProvider : ISwaggerProvider
1313
{
1414
private readonly SwaggerGenerator _defaultSwaggerGenerator;
1515
private readonly ConcurrentDictionary<string, OpenApiDocument> _openApiDocumentCache = new();
1616

17-
public CachingSwaggerGenerator(SwaggerGenerator defaultSwaggerGenerator)
17+
public CachingSwaggerProvider(SwaggerGenerator defaultSwaggerGenerator)
1818
{
1919
ArgumentGuard.NotNull(defaultSwaggerGenerator);
2020

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public JsonApiSchemaGenerator(SchemaGenerator defaultSchemaGenerator, IResourceG
6363
_defaultSchemaGenerator = defaultSchemaGenerator;
6464
_options = options;
6565

66-
_resourceObjectSchemaGenerator = new ResourceObjectSchemaGenerator(defaultSchemaGenerator, resourceGraph, options, _schemaRepositoryAccessor,
66+
_resourceObjectSchemaGenerator = new ResourceObjectSchemaGenerator(defaultSchemaGenerator, _schemaRepositoryAccessor, resourceGraph, options,
6767
resourceFieldValidationMetadataProvider);
6868
}
6969

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs

Lines changed: 15 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Reflection;
2-
using JsonApiDotNetCore.Configuration;
32
using JsonApiDotNetCore.OpenApi.JsonApiMetadata;
43
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Relationships;
54
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
@@ -31,31 +30,31 @@ internal sealed class ResourceFieldObjectSchemaBuilder
3130
JsonApiPropertyName.Meta
3231
];
3332

34-
private readonly ResourceTypeInfo _resourceTypeInfo;
35-
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
3633
private readonly SchemaGenerator _defaultSchemaGenerator;
37-
private readonly ResourceTypeSchemaGenerator _resourceTypeSchemaGenerator;
38-
private readonly SchemaRepository _resourceSchemaRepository = new();
39-
private readonly IDictionary<string, OpenApiSchema> _schemasForResourceFields;
34+
private readonly ResourceIdentifierObjectSchemaGenerator _resourceIdentifierObjectSchemaGenerator;
35+
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
36+
private readonly ResourceTypeInfo _resourceTypeInfo;
4037
private readonly ResourceFieldValidationMetadataProvider _resourceFieldValidationMetadataProvider;
38+
private readonly SchemaRepository _resourceSchemaRepository = new();
4139
private readonly RelationshipTypeFactory _relationshipTypeFactory;
40+
private readonly IDictionary<string, OpenApiSchema> _schemasForResourceFields;
4241
private readonly NullabilityInfoContext _nullabilityInfoContext = new();
4342
private readonly ResourceObjectDocumentationReader _resourceObjectDocumentationReader;
4443

45-
public ResourceFieldObjectSchemaBuilder(ResourceTypeInfo resourceTypeInfo, ISchemaRepositoryAccessor schemaRepositoryAccessor,
46-
SchemaGenerator defaultSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator,
47-
ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider)
44+
public ResourceFieldObjectSchemaBuilder(SchemaGenerator defaultSchemaGenerator,
45+
ResourceIdentifierObjectSchemaGenerator resourceIdentifierObjectSchemaGenerator, ISchemaRepositoryAccessor schemaRepositoryAccessor,
46+
ResourceTypeInfo resourceTypeInfo, ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider)
4847
{
49-
ArgumentGuard.NotNull(resourceTypeInfo);
50-
ArgumentGuard.NotNull(schemaRepositoryAccessor);
5148
ArgumentGuard.NotNull(defaultSchemaGenerator);
52-
ArgumentGuard.NotNull(resourceTypeSchemaGenerator);
49+
ArgumentGuard.NotNull(resourceIdentifierObjectSchemaGenerator);
50+
ArgumentGuard.NotNull(schemaRepositoryAccessor);
51+
ArgumentGuard.NotNull(resourceTypeInfo);
5352
ArgumentGuard.NotNull(resourceFieldValidationMetadataProvider);
5453

55-
_resourceTypeInfo = resourceTypeInfo;
56-
_schemaRepositoryAccessor = schemaRepositoryAccessor;
5754
_defaultSchemaGenerator = defaultSchemaGenerator;
58-
_resourceTypeSchemaGenerator = resourceTypeSchemaGenerator;
55+
_resourceIdentifierObjectSchemaGenerator = resourceIdentifierObjectSchemaGenerator;
56+
_schemaRepositoryAccessor = schemaRepositoryAccessor;
57+
_resourceTypeInfo = resourceTypeInfo;
5958
_resourceFieldValidationMetadataProvider = resourceFieldValidationMetadataProvider;
6059

6160
_relationshipTypeFactory = new RelationshipTypeFactory(resourceFieldValidationMetadataProvider);
@@ -160,38 +159,12 @@ public void SetMembersOfRelationshipsObject(OpenApiSchema fullSchemaForRelations
160159

161160
if (matchingRelationship != null)
162161
{
163-
EnsureResourceIdentifierObjectSchemaExists(matchingRelationship);
162+
_ = _resourceIdentifierObjectSchemaGenerator.GenerateSchema(matchingRelationship.RightType);
164163
AddRelationshipSchemaToResourceObject(matchingRelationship, fullSchemaForRelationshipsObject);
165164
}
166165
}
167166
}
168167

169-
private void EnsureResourceIdentifierObjectSchemaExists(RelationshipAttribute relationship)
170-
{
171-
Type resourceIdentifierObjectType = typeof(ResourceIdentifierObject<>).MakeGenericType(relationship.RightType.ClrType);
172-
173-
if (!ResourceIdentifierObjectSchemaExists(resourceIdentifierObjectType))
174-
{
175-
GenerateResourceIdentifierObjectSchema(resourceIdentifierObjectType, relationship.RightType);
176-
}
177-
}
178-
179-
private bool ResourceIdentifierObjectSchemaExists(Type resourceIdentifierObjectType)
180-
{
181-
return _schemaRepositoryAccessor.Current.TryLookupByType(resourceIdentifierObjectType, out _);
182-
}
183-
184-
private void GenerateResourceIdentifierObjectSchema(Type resourceIdentifierObjectType, ResourceType resourceType)
185-
{
186-
OpenApiSchema referenceSchemaForResourceIdentifierObject =
187-
_defaultSchemaGenerator.GenerateSchema(resourceIdentifierObjectType, _schemaRepositoryAccessor.Current);
188-
189-
OpenApiSchema fullSchemaForResourceIdentifierObject =
190-
_schemaRepositoryAccessor.Current.Schemas[referenceSchemaForResourceIdentifierObject.Reference.Id];
191-
192-
fullSchemaForResourceIdentifierObject.Properties[JsonApiPropertyName.Type] = _resourceTypeSchemaGenerator.Get(resourceType);
193-
}
194-
195168
private void AddRelationshipSchemaToResourceObject(RelationshipAttribute relationship, OpenApiSchema fullSchemaForRelationshipsObject)
196169
{
197170
Type relationshipSchemaType = GetRelationshipSchemaType(relationship, _resourceTypeInfo.ResourceObjectOpenType);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using JsonApiDotNetCore.Configuration;
2+
using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects;
3+
using Microsoft.OpenApi.Models;
4+
using Swashbuckle.AspNetCore.SwaggerGen;
5+
6+
namespace JsonApiDotNetCore.OpenApi.SwaggerComponents;
7+
8+
internal sealed class ResourceIdentifierObjectSchemaGenerator
9+
{
10+
private readonly SchemaGenerator _defaultSchemaGenerator;
11+
private readonly ResourceTypeSchemaGenerator _resourceTypeSchemaGenerator;
12+
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
13+
14+
public ResourceIdentifierObjectSchemaGenerator(SchemaGenerator defaultSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator,
15+
ISchemaRepositoryAccessor schemaRepositoryAccessor)
16+
{
17+
ArgumentGuard.NotNull(defaultSchemaGenerator);
18+
ArgumentGuard.NotNull(resourceTypeSchemaGenerator);
19+
ArgumentGuard.NotNull(schemaRepositoryAccessor);
20+
21+
_defaultSchemaGenerator = defaultSchemaGenerator;
22+
_resourceTypeSchemaGenerator = resourceTypeSchemaGenerator;
23+
_schemaRepositoryAccessor = schemaRepositoryAccessor;
24+
}
25+
26+
public OpenApiSchema GenerateSchema(ResourceType resourceType)
27+
{
28+
ArgumentGuard.NotNull(resourceType);
29+
30+
Type resourceIdentifierObjectType = typeof(ResourceIdentifierObject<>).MakeGenericType(resourceType.ClrType);
31+
32+
if (!_schemaRepositoryAccessor.Current.TryLookupByType(resourceIdentifierObjectType, out OpenApiSchema? referenceSchemaForResourceIdentifierObject))
33+
{
34+
referenceSchemaForResourceIdentifierObject =
35+
_defaultSchemaGenerator.GenerateSchema(resourceIdentifierObjectType, _schemaRepositoryAccessor.Current);
36+
37+
OpenApiSchema fullSchemaForResourceIdentifierObject =
38+
_schemaRepositoryAccessor.Current.Schemas[referenceSchemaForResourceIdentifierObject.Reference.Id];
39+
40+
fullSchemaForResourceIdentifierObject.Properties[JsonApiPropertyName.Type] = _resourceTypeSchemaGenerator.Get(resourceType);
41+
}
42+
43+
return referenceSchemaForResourceIdentifierObject;
44+
}
45+
}

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,33 @@ internal sealed class ResourceObjectSchemaGenerator
1818
];
1919

2020
private readonly SchemaGenerator _defaultSchemaGenerator;
21+
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
2122
private readonly IResourceGraph _resourceGraph;
2223
private readonly IJsonApiOptions _options;
23-
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
2424
private readonly ResourceTypeSchemaGenerator _resourceTypeSchemaGenerator;
2525
private readonly Func<ResourceTypeInfo, ResourceFieldObjectSchemaBuilder> _resourceFieldObjectSchemaBuilderFactory;
2626
private readonly ResourceObjectDocumentationReader _resourceObjectDocumentationReader;
2727

28-
public ResourceObjectSchemaGenerator(SchemaGenerator defaultSchemaGenerator, IResourceGraph resourceGraph, IJsonApiOptions options,
29-
ISchemaRepositoryAccessor schemaRepositoryAccessor, ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider)
28+
public ResourceObjectSchemaGenerator(SchemaGenerator defaultSchemaGenerator, ISchemaRepositoryAccessor schemaRepositoryAccessor,
29+
IResourceGraph resourceGraph, IJsonApiOptions options, ResourceFieldValidationMetadataProvider resourceFieldValidationMetadataProvider)
3030
{
3131
ArgumentGuard.NotNull(defaultSchemaGenerator);
32+
ArgumentGuard.NotNull(schemaRepositoryAccessor);
3233
ArgumentGuard.NotNull(resourceGraph);
3334
ArgumentGuard.NotNull(options);
34-
ArgumentGuard.NotNull(schemaRepositoryAccessor);
3535
ArgumentGuard.NotNull(resourceFieldValidationMetadataProvider);
3636

3737
_defaultSchemaGenerator = defaultSchemaGenerator;
38+
_schemaRepositoryAccessor = schemaRepositoryAccessor;
3839
_resourceGraph = resourceGraph;
3940
_options = options;
40-
_schemaRepositoryAccessor = schemaRepositoryAccessor;
4141
_resourceTypeSchemaGenerator = new ResourceTypeSchemaGenerator(schemaRepositoryAccessor, options.SerializerOptions.PropertyNamingPolicy);
4242

43-
_resourceFieldObjectSchemaBuilderFactory = resourceTypeInfo => new ResourceFieldObjectSchemaBuilder(resourceTypeInfo, schemaRepositoryAccessor,
44-
defaultSchemaGenerator, _resourceTypeSchemaGenerator, resourceFieldValidationMetadataProvider);
43+
var resourceIdentifierObjectSchemaGenerator =
44+
new ResourceIdentifierObjectSchemaGenerator(defaultSchemaGenerator, _resourceTypeSchemaGenerator, schemaRepositoryAccessor);
45+
46+
_resourceFieldObjectSchemaBuilderFactory = resourceTypeInfo => new ResourceFieldObjectSchemaBuilder(defaultSchemaGenerator,
47+
resourceIdentifierObjectSchemaGenerator, schemaRepositoryAccessor, resourceTypeInfo, resourceFieldValidationMetadataProvider);
4548

4649
_resourceObjectDocumentationReader = new ResourceObjectDocumentationReader();
4750
}

src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace JsonApiDotNetCore.OpenApi.SwaggerComponents;
99
internal sealed class ResourceTypeSchemaGenerator
1010
{
1111
private const string ResourceTypeSchemaIdTemplate = "[ResourceName] Resource Type";
12+
1213
private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor;
1314
private readonly JsonNamingPolicy? _namingPolicy;
1415
private readonly Dictionary<Type, OpenApiSchema> _resourceClrTypeSchemaCache = [];

0 commit comments

Comments
 (0)