Skip to content

Commit df25522

Browse files
committed
Process review feedback
1 parent e07903c commit df25522

32 files changed

+832
-324
lines changed

Diff for: src/JsonApiDotNetCore.OpenApi/JsonApiActionDescriptorCollectionProvider.cs

+25-28
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
5-
using JsonApiDotNetCore.Configuration;
65
using JsonApiDotNetCore.Middleware;
76
using JsonApiDotNetCore.OpenApi.JsonApiMetadata;
87
using Microsoft.AspNetCore.Mvc;
@@ -26,15 +25,14 @@ internal sealed class JsonApiActionDescriptorCollectionProvider : IActionDescrip
2625

2726
public ActionDescriptorCollection ActionDescriptors => GetActionDescriptors();
2827

29-
public JsonApiActionDescriptorCollectionProvider(IResourceGraph resourceGraph, IControllerResourceMapping controllerResourceMapping,
28+
public JsonApiActionDescriptorCollectionProvider(IControllerResourceMapping controllerResourceMapping,
3029
IActionDescriptorCollectionProvider defaultProvider)
3130
{
32-
ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph));
3331
ArgumentGuard.NotNull(controllerResourceMapping, nameof(controllerResourceMapping));
3432
ArgumentGuard.NotNull(defaultProvider, nameof(defaultProvider));
3533

3634
_defaultProvider = defaultProvider;
37-
_jsonApiEndpointMetadataProvider = new JsonApiEndpointMetadataProvider(resourceGraph, controllerResourceMapping);
35+
_jsonApiEndpointMetadataProvider = new JsonApiEndpointMetadataProvider(controllerResourceMapping);
3836
}
3937

4038
private ActionDescriptorCollection GetActionDescriptors()
@@ -67,27 +65,26 @@ private static bool IsVisibleJsonApiEndpoint(ActionDescriptor descriptor)
6765
return descriptor is ControllerActionDescriptor controllerAction && controllerAction.Properties.ContainsKey(typeof(ApiDescriptionActionData));
6866
}
6967

70-
private static IList<ActionDescriptor> AddJsonApiMetadataToAction(ActionDescriptor endpoint, IJsonApiEndpointMetadata? jsonApiEndpointMetadata)
68+
private static IEnumerable<ActionDescriptor> AddJsonApiMetadataToAction(ActionDescriptor endpoint, IJsonApiEndpointMetadata? jsonApiEndpointMetadata)
7169
{
7270
switch (jsonApiEndpointMetadata)
7371
{
7472
case PrimaryResponseMetadata primaryMetadata:
7573
{
76-
UpdateProducesResponseTypeAttribute(endpoint, primaryMetadata.Type);
74+
UpdateProducesResponseTypeAttribute(endpoint, primaryMetadata.DocumentType);
7775
return Array.Empty<ActionDescriptor>();
7876
}
7977
case PrimaryRequestMetadata primaryMetadata:
8078
{
81-
UpdateBodyParameterDescriptor(endpoint, primaryMetadata.Type);
79+
UpdateBodyParameterDescriptor(endpoint, primaryMetadata.DocumentType);
8280
return Array.Empty<ActionDescriptor>();
8381
}
84-
case ExpansibleEndpointMetadata expansibleMetadata
85-
when expansibleMetadata is RelationshipResponseMetadata || expansibleMetadata is SecondaryResponseMetadata:
82+
case ExpansibleEndpointMetadata expansibleMetadata and (RelationshipResponseMetadata or SecondaryResponseMetadata):
8683
{
8784
return Expand(endpoint, expansibleMetadata,
88-
(expandedEndpoint, relationshipType, _) => UpdateProducesResponseTypeAttribute(expandedEndpoint, relationshipType));
85+
(expandedEndpoint, documentType, _) => UpdateProducesResponseTypeAttribute(expandedEndpoint, documentType));
8986
}
90-
case ExpansibleEndpointMetadata expansibleMetadata when expansibleMetadata is RelationshipRequestMetadata:
87+
case ExpansibleEndpointMetadata expansibleMetadata and RelationshipRequestMetadata:
9188
{
9289
return Expand(endpoint, expansibleMetadata, UpdateBodyParameterDescriptor);
9390
}
@@ -98,56 +95,56 @@ private static IList<ActionDescriptor> AddJsonApiMetadataToAction(ActionDescript
9895
}
9996
}
10097

101-
private static void UpdateProducesResponseTypeAttribute(ActionDescriptor endpoint, Type responseTypeToSet)
98+
private static void UpdateProducesResponseTypeAttribute(ActionDescriptor endpoint, Type responseDocumentType)
10299
{
103-
if (ProducesJsonApiResponseBody(endpoint))
100+
if (ProducesJsonApiResponseDocument(endpoint))
104101
{
105102
var producesResponse = endpoint.GetFilterMetadata<ProducesResponseTypeAttribute>();
106103

107104
if (producesResponse != null)
108105
{
109-
producesResponse.Type = responseTypeToSet;
110-
106+
producesResponse.Type = responseDocumentType;
111107
return;
112108
}
113109
}
114110

115111
throw new UnreachableCodeException();
116112
}
117113

118-
private static bool ProducesJsonApiResponseBody(ActionDescriptor endpoint)
114+
private static bool ProducesJsonApiResponseDocument(ActionDescriptor endpoint)
119115
{
120116
var produces = endpoint.GetFilterMetadata<ProducesAttribute>();
121117

122118
return produces != null && produces.ContentTypes.Any(contentType => contentType == HeaderConstants.MediaType);
123119
}
124120

125-
private static IList<ActionDescriptor> Expand(ActionDescriptor genericEndpoint, ExpansibleEndpointMetadata metadata,
121+
private static IEnumerable<ActionDescriptor> Expand(ActionDescriptor genericEndpoint, ExpansibleEndpointMetadata metadata,
126122
Action<ActionDescriptor, Type, string> expansionCallback)
127123
{
128124
var expansion = new List<ActionDescriptor>();
129125

130-
foreach ((string relationshipName, Type relationshipType) in metadata.ExpansionElements)
126+
foreach ((string relationshipName, Type documentType) in metadata.DocumentTypesByRelationshipName)
131127
{
132-
ActionDescriptor expandedEndpoint = Clone(genericEndpoint);
133-
RemovePathParameter(expandedEndpoint.Parameters, JsonApiPathParameter.RelationshipName);
134-
135-
if (expandedEndpoint.AttributeRouteInfo == null)
128+
if (genericEndpoint.AttributeRouteInfo == null)
136129
{
137-
throw new NotSupportedException("Only attribute based routing is supported for JsonApiDotNetCore endpoints");
130+
throw new NotSupportedException("Only attribute routing is supported for JsonApiDotNetCore endpoints.");
138131
}
139132

140-
ExpandTemplate(expandedEndpoint.AttributeRouteInfo, relationshipName);
133+
ActionDescriptor expandedEndpoint = Clone(genericEndpoint);
134+
135+
RemovePathParameter(expandedEndpoint.Parameters, JsonApiPathParameter.RelationshipName);
136+
137+
ExpandTemplate(expandedEndpoint.AttributeRouteInfo!, relationshipName);
141138

142-
expansionCallback(expandedEndpoint, relationshipType, relationshipName);
139+
expansionCallback(expandedEndpoint, documentType, relationshipName);
143140

144141
expansion.Add(expandedEndpoint);
145142
}
146143

147144
return expansion;
148145
}
149146

150-
private static void UpdateBodyParameterDescriptor(ActionDescriptor endpoint, Type bodyType, string? parameterName = null)
147+
private static void UpdateBodyParameterDescriptor(ActionDescriptor endpoint, Type documentType, string? parameterName = null)
151148
{
152149
ControllerParameterDescriptor? requestBodyDescriptor = endpoint.GetBodyParameterDescriptor();
153150

@@ -157,8 +154,8 @@ private static void UpdateBodyParameterDescriptor(ActionDescriptor endpoint, Typ
157154
throw new UnreachableCodeException();
158155
}
159156

160-
requestBodyDescriptor.ParameterType = bodyType;
161-
ParameterInfo replacementParameterInfo = requestBodyDescriptor.ParameterInfo.WithParameterType(bodyType);
157+
requestBodyDescriptor.ParameterType = documentType;
158+
ParameterInfo replacementParameterInfo = requestBodyDescriptor.ParameterInfo.WithParameterType(documentType);
162159

163160
if (parameterName != null)
164161
{

Diff for: src/JsonApiDotNetCore.OpenApi/JsonApiMetadata/ExpansibleEndpointMetadata.cs

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiMetadata
55
{
66
internal abstract class ExpansibleEndpointMetadata
77
{
8-
public abstract IDictionary<string, Type> ExpansionElements { get; }
8+
public IDictionary<string, Type> DocumentTypesByRelationshipName { get; }
9+
10+
protected ExpansibleEndpointMetadata(IDictionary<string, Type> documentTypesByRelationshipName)
11+
{
12+
ArgumentGuard.NotNull(documentTypesByRelationshipName, nameof(documentTypesByRelationshipName));
13+
14+
DocumentTypesByRelationshipName = documentTypesByRelationshipName;
15+
}
916
}
1017
}

Diff for: src/JsonApiDotNetCore.OpenApi/JsonApiMetadata/JsonApiEndpointMetadataProvider.cs

+32-57
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
using System.Reflection;
55
using JsonApiDotNetCore.Configuration;
66
using JsonApiDotNetCore.Middleware;
7+
using JsonApiDotNetCore.OpenApi.JsonApiObjects;
78
using JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents;
8-
using JsonApiDotNetCore.OpenApi.JsonApiObjects.RelationshipData;
99
using JsonApiDotNetCore.Resources.Annotations;
1010

1111
namespace JsonApiDotNetCore.OpenApi.JsonApiMetadata
@@ -16,16 +16,14 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiMetadata
1616
/// </summary>
1717
internal sealed class JsonApiEndpointMetadataProvider
1818
{
19-
private readonly IResourceGraph _resourceGraph;
2019
private readonly IControllerResourceMapping _controllerResourceMapping;
2120
private readonly EndpointResolver _endpointResolver = new();
21+
private readonly NonPrimaryDocumentTypeFactory _nonPrimaryDocumentTypeFactory = new();
2222

23-
public JsonApiEndpointMetadataProvider(IResourceGraph resourceGraph, IControllerResourceMapping controllerResourceMapping)
23+
public JsonApiEndpointMetadataProvider(IControllerResourceMapping controllerResourceMapping)
2424
{
25-
ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph));
2625
ArgumentGuard.NotNull(controllerResourceMapping, nameof(controllerResourceMapping));
2726

28-
_resourceGraph = resourceGraph;
2927
_controllerResourceMapping = controllerResourceMapping;
3028
}
3129

@@ -47,28 +45,28 @@ public JsonApiEndpointMetadataContainer Get(MethodInfo controllerAction)
4745
throw new UnreachableCodeException();
4846
}
4947

50-
IJsonApiRequestMetadata? requestMetadata = GetRequestMetadata(endpoint.Value, primaryResourceType.ClrType);
51-
IJsonApiResponseMetadata? responseMetadata = GetResponseMetadata(endpoint.Value, primaryResourceType.ClrType);
48+
IJsonApiRequestMetadata? requestMetadata = GetRequestMetadata(endpoint.Value, primaryResourceType);
49+
IJsonApiResponseMetadata? responseMetadata = GetResponseMetadata(endpoint.Value, primaryResourceType);
5250
return new JsonApiEndpointMetadataContainer(requestMetadata, responseMetadata);
5351
}
5452

55-
private IJsonApiRequestMetadata? GetRequestMetadata(JsonApiEndpoint endpoint, Type primaryResourceType)
53+
private IJsonApiRequestMetadata? GetRequestMetadata(JsonApiEndpoint endpoint, ResourceType primaryResourceType)
5654
{
5755
switch (endpoint)
5856
{
5957
case JsonApiEndpoint.Post:
6058
{
61-
return GetPostRequestMetadata(primaryResourceType);
59+
return GetPostRequestMetadata(primaryResourceType.ClrType);
6260
}
6361
case JsonApiEndpoint.Patch:
6462
{
65-
return GetPatchRequestMetadata(primaryResourceType);
63+
return GetPatchRequestMetadata(primaryResourceType.ClrType);
6664
}
6765
case JsonApiEndpoint.PostRelationship:
6866
case JsonApiEndpoint.PatchRelationship:
6967
case JsonApiEndpoint.DeleteRelationship:
7068
{
71-
return GetRelationshipRequestMetadata(primaryResourceType, endpoint != JsonApiEndpoint.PatchRelationship);
69+
return GetRelationshipRequestMetadata(primaryResourceType.Relationships, endpoint != JsonApiEndpoint.PatchRelationship);
7270
}
7371
default:
7472
{
@@ -77,38 +75,31 @@ public JsonApiEndpointMetadataContainer Get(MethodInfo controllerAction)
7775
}
7876
}
7977

80-
private static PrimaryRequestMetadata GetPostRequestMetadata(Type primaryResourceType)
78+
private static PrimaryRequestMetadata GetPostRequestMetadata(Type resourceClrType)
8179
{
82-
Type documentType = typeof(ResourcePostRequestDocument<>).MakeGenericType(primaryResourceType);
80+
Type documentType = typeof(ResourcePostRequestDocument<>).MakeGenericType(resourceClrType);
8381

8482
return new PrimaryRequestMetadata(documentType);
8583
}
8684

87-
private static PrimaryRequestMetadata GetPatchRequestMetadata(Type primaryResourceType)
85+
private static PrimaryRequestMetadata GetPatchRequestMetadata(Type resourceClrType)
8886
{
89-
Type documentType = typeof(ResourcePatchRequestDocument<>).MakeGenericType(primaryResourceType);
87+
Type documentType = typeof(ResourcePatchRequestDocument<>).MakeGenericType(resourceClrType);
9088

9189
return new PrimaryRequestMetadata(documentType);
9290
}
9391

94-
private RelationshipRequestMetadata GetRelationshipRequestMetadata(Type primaryResourceType, bool ignoreHasOneRelationships)
92+
private RelationshipRequestMetadata GetRelationshipRequestMetadata(IEnumerable<RelationshipAttribute> relationships, bool ignoreHasOneRelationships)
9593
{
96-
IEnumerable<RelationshipAttribute> relationships = _resourceGraph.GetResourceType(primaryResourceType).Relationships;
94+
IEnumerable<RelationshipAttribute> relationshipsOfEndpoint = ignoreHasOneRelationships ? relationships.OfType<HasManyAttribute>() : relationships;
9795

98-
if (ignoreHasOneRelationships)
99-
{
100-
relationships = relationships.OfType<HasManyAttribute>();
101-
}
102-
103-
IDictionary<string, Type> resourceTypesByRelationshipName = relationships.ToDictionary(relationship => relationship.PublicName,
104-
relationship => relationship is HasManyAttribute
105-
? typeof(ToManyRelationshipRequestData<>).MakeGenericType(relationship.RightType.ClrType)
106-
: typeof(ToOneRelationshipRequestData<>).MakeGenericType(relationship.RightType.ClrType));
96+
IDictionary<string, Type> requestDocumentTypesByRelationshipName = relationshipsOfEndpoint.ToDictionary(relationship => relationship.PublicName,
97+
_nonPrimaryDocumentTypeFactory.GetForRelationshipRequest);
10798

108-
return new RelationshipRequestMetadata(resourceTypesByRelationshipName);
99+
return new RelationshipRequestMetadata(requestDocumentTypesByRelationshipName);
109100
}
110101

111-
private IJsonApiResponseMetadata? GetResponseMetadata(JsonApiEndpoint endpoint, Type primaryResourceType)
102+
private IJsonApiResponseMetadata? GetResponseMetadata(JsonApiEndpoint endpoint, ResourceType primaryResourceType)
112103
{
113104
switch (endpoint)
114105
{
@@ -117,15 +108,15 @@ private RelationshipRequestMetadata GetRelationshipRequestMetadata(Type primaryR
117108
case JsonApiEndpoint.Post:
118109
case JsonApiEndpoint.Patch:
119110
{
120-
return GetPrimaryResponseMetadata(primaryResourceType, endpoint == JsonApiEndpoint.GetCollection);
111+
return GetPrimaryResponseMetadata(primaryResourceType.ClrType, endpoint == JsonApiEndpoint.GetCollection);
121112
}
122113
case JsonApiEndpoint.GetSecondary:
123114
{
124-
return GetSecondaryResponseMetadata(primaryResourceType);
115+
return GetSecondaryResponseMetadata(primaryResourceType.Relationships);
125116
}
126117
case JsonApiEndpoint.GetRelationship:
127118
{
128-
return GetRelationshipResponseMetadata(primaryResourceType);
119+
return GetRelationshipResponseMetadata(primaryResourceType.Relationships);
129120
}
130121
default:
131122
{
@@ -134,44 +125,28 @@ private RelationshipRequestMetadata GetRelationshipRequestMetadata(Type primaryR
134125
}
135126
}
136127

137-
private static PrimaryResponseMetadata GetPrimaryResponseMetadata(Type primaryResourceType, bool endpointReturnsCollection)
128+
private static PrimaryResponseMetadata GetPrimaryResponseMetadata(Type resourceClrType, bool endpointReturnsCollection)
138129
{
139130
Type documentOpenType = endpointReturnsCollection ? typeof(ResourceCollectionResponseDocument<>) : typeof(PrimaryResourceResponseDocument<>);
140-
Type documentType = documentOpenType.MakeGenericType(primaryResourceType);
131+
Type documentType = documentOpenType.MakeGenericType(resourceClrType);
141132

142133
return new PrimaryResponseMetadata(documentType);
143134
}
144135

145-
private SecondaryResponseMetadata GetSecondaryResponseMetadata(Type primaryResourceType)
146-
{
147-
IDictionary<string, Type> responseTypesByRelationshipName = GetMetadataByRelationshipName(primaryResourceType, relationship =>
148-
{
149-
Type documentType = relationship is HasManyAttribute
150-
? typeof(ResourceCollectionResponseDocument<>)
151-
: typeof(SecondaryResourceResponseDocument<>);
152-
153-
return documentType.MakeGenericType(relationship.RightType.ClrType);
154-
});
155-
156-
return new SecondaryResponseMetadata(responseTypesByRelationshipName);
157-
}
158-
159-
private IDictionary<string, Type> GetMetadataByRelationshipName(Type primaryResourceType,
160-
Func<RelationshipAttribute, Type> extractRelationshipMetadataCallback)
136+
private SecondaryResponseMetadata GetSecondaryResponseMetadata(IEnumerable<RelationshipAttribute> relationships)
161137
{
162-
IReadOnlyCollection<RelationshipAttribute> relationships = _resourceGraph.GetResourceType(primaryResourceType).Relationships;
138+
IDictionary<string, Type> responseDocumentTypesByRelationshipName = relationships.ToDictionary(relationship => relationship.PublicName,
139+
_nonPrimaryDocumentTypeFactory.GetForSecondaryResponse);
163140

164-
return relationships.ToDictionary(relationship => relationship.PublicName, extractRelationshipMetadataCallback);
141+
return new SecondaryResponseMetadata(responseDocumentTypesByRelationshipName);
165142
}
166143

167-
private RelationshipResponseMetadata GetRelationshipResponseMetadata(Type primaryResourceType)
144+
private RelationshipResponseMetadata GetRelationshipResponseMetadata(IEnumerable<RelationshipAttribute> relationships)
168145
{
169-
IDictionary<string, Type> responseTypesByRelationshipName = GetMetadataByRelationshipName(primaryResourceType,
170-
relationship => relationship is HasManyAttribute
171-
? typeof(ResourceIdentifierCollectionResponseDocument<>).MakeGenericType(relationship.RightType.ClrType)
172-
: typeof(ResourceIdentifierResponseDocument<>).MakeGenericType(relationship.RightType.ClrType));
146+
IDictionary<string, Type> responseDocumentTypesByRelationshipName = relationships.ToDictionary(relationship => relationship.PublicName,
147+
_nonPrimaryDocumentTypeFactory.GetForRelationshipResponse);
173148

174-
return new RelationshipResponseMetadata(responseTypesByRelationshipName);
149+
return new RelationshipResponseMetadata(responseDocumentTypesByRelationshipName);
175150
}
176151
}
177152
}

Diff for: src/JsonApiDotNetCore.OpenApi/JsonApiMetadata/PrimaryRequestMetadata.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiMetadata
44
{
55
internal sealed class PrimaryRequestMetadata : IJsonApiRequestMetadata
66
{
7-
public Type Type { get; }
7+
public Type DocumentType { get; }
88

9-
public PrimaryRequestMetadata(Type type)
9+
public PrimaryRequestMetadata(Type documentType)
1010
{
11-
ArgumentGuard.NotNull(type, nameof(type));
11+
ArgumentGuard.NotNull(documentType, nameof(documentType));
1212

13-
Type = type;
13+
DocumentType = documentType;
1414
}
1515
}
1616
}

0 commit comments

Comments
 (0)