@@ -92,7 +92,7 @@ public JsonApiEndpointMetadata Get(ActionDescriptor descriptor)
9292 JsonApiEndpoints . Post => GetPostResourceRequestMetadata ( primaryResourceType . ClrType ) ,
9393 JsonApiEndpoints . Patch => GetPatchResourceRequestMetadata ( primaryResourceType . ClrType ) ,
9494 JsonApiEndpoints . PostRelationship or JsonApiEndpoints . PatchRelationship or JsonApiEndpoints . DeleteRelationship => GetRelationshipRequestMetadata (
95- primaryResourceType . Relationships , endpoint != JsonApiEndpoints . PatchRelationship ) ,
95+ endpoint , primaryResourceType . Relationships ) ,
9696 _ => null
9797 } ;
9898 }
@@ -111,16 +111,29 @@ private static PrimaryRequestMetadata GetPatchResourceRequestMetadata(Type resou
111111 return new PrimaryRequestMetadata ( documentType ) ;
112112 }
113113
114- private RelationshipRequestMetadata GetRelationshipRequestMetadata ( IReadOnlyCollection < RelationshipAttribute > relationships , bool ignoreHasOneRelationships )
114+ private RelationshipRequestMetadata GetRelationshipRequestMetadata ( JsonApiEndpoints endpoint , IReadOnlyCollection < RelationshipAttribute > relationships )
115115 {
116- IEnumerable < RelationshipAttribute > relationshipsOfEndpoint = ignoreHasOneRelationships ? relationships . OfType < HasManyAttribute > ( ) : relationships ;
116+ IEnumerable < RelationshipAttribute > relationshipsOfEndpoint = FilterRelationshipsForEndpoint ( endpoint , relationships ) ;
117117
118118 Dictionary < RelationshipAttribute , Type > documentTypesByRelationship = relationshipsOfEndpoint . ToDictionary ( relationship => relationship ,
119119 _nonPrimaryDocumentTypeFactory . GetForRelationshipRequest ) ;
120120
121121 return new RelationshipRequestMetadata ( documentTypesByRelationship . AsReadOnly ( ) ) ;
122122 }
123123
124+ private static IEnumerable < RelationshipAttribute > FilterRelationshipsForEndpoint ( JsonApiEndpoints endpoint ,
125+ IReadOnlyCollection < RelationshipAttribute > relationships )
126+ {
127+ return endpoint switch
128+ {
129+ JsonApiEndpoints . GetRelationship => relationships . Where ( relationship => ! relationship . IsViewBlocked ( ) ) ,
130+ JsonApiEndpoints . PatchRelationship => relationships . Where ( relationship => ! relationship . IsSetBlocked ( ) ) ,
131+ JsonApiEndpoints . PostRelationship => relationships . OfType < HasManyAttribute > ( ) . Where ( relationship => ! relationship . IsAddBlocked ( ) ) ,
132+ JsonApiEndpoints . DeleteRelationship => relationships . OfType < HasManyAttribute > ( ) . Where ( relationship => ! relationship . IsRemoveBlocked ( ) ) ,
133+ _ => relationships
134+ } ;
135+ }
136+
124137 private IJsonApiResponseMetadata ? GetResponseMetadata ( JsonApiEndpoints endpoint , ResourceType primaryResourceType ,
125138 ReadOnlyCollection < HttpStatusCode > successStatusCodes , ReadOnlyCollection < HttpStatusCode > errorStatusCodes )
126139 {
@@ -131,11 +144,9 @@ private RelationshipRequestMetadata GetRelationshipRequestMetadata(IReadOnlyColl
131144 successStatusCodes , errorStatusCodes ) ,
132145 JsonApiEndpoints . Delete => GetEmptyPrimaryResponseMetadata ( successStatusCodes , errorStatusCodes ) ,
133146 JsonApiEndpoints . GetSecondary => GetSecondaryResponseMetadata ( primaryResourceType . Relationships , successStatusCodes , errorStatusCodes ) ,
134- JsonApiEndpoints . GetRelationship => GetRelationshipResponseMetadata ( primaryResourceType . Relationships , false , successStatusCodes , errorStatusCodes ) ,
135- JsonApiEndpoints . PatchRelationship => GetEmptyRelationshipResponseMetadata ( primaryResourceType . Relationships , false , successStatusCodes ,
136- errorStatusCodes ) ,
137- JsonApiEndpoints . PostRelationship or JsonApiEndpoints . DeleteRelationship => GetEmptyRelationshipResponseMetadata ( primaryResourceType . Relationships ,
138- true , successStatusCodes , errorStatusCodes ) ,
147+ JsonApiEndpoints . GetRelationship => GetRelationshipResponseMetadata ( primaryResourceType . Relationships , successStatusCodes , errorStatusCodes ) ,
148+ JsonApiEndpoints . PatchRelationship or JsonApiEndpoints . PostRelationship or JsonApiEndpoints . DeleteRelationship =>
149+ GetEmptyRelationshipResponseMetadata ( endpoint , primaryResourceType . Relationships , successStatusCodes , errorStatusCodes ) ,
139150 _ => null
140151 } ;
141152 }
@@ -238,24 +249,23 @@ private SecondaryResponseMetadata GetSecondaryResponseMetadata(IEnumerable<Relat
238249 }
239250
240251 private RelationshipResponseMetadata GetRelationshipResponseMetadata ( IReadOnlyCollection < RelationshipAttribute > relationships ,
241- bool ignoreHasOneRelationships , ReadOnlyCollection < HttpStatusCode > successStatusCodes , ReadOnlyCollection < HttpStatusCode > errorStatusCodes )
252+ ReadOnlyCollection < HttpStatusCode > successStatusCodes , ReadOnlyCollection < HttpStatusCode > errorStatusCodes )
242253 {
243- IReadOnlyCollection < RelationshipAttribute > relationshipsOfEndpoint =
244- ignoreHasOneRelationships ? relationships . OfType < HasManyAttribute > ( ) . ToList ( ) . AsReadOnly ( ) : relationships ;
254+ IEnumerable < RelationshipAttribute > relationshipsOfEndpoint = FilterRelationshipsForEndpoint ( JsonApiEndpoints . GetRelationship , relationships ) ;
245255
246256 Dictionary < RelationshipAttribute , Type > documentTypesByRelationship = relationshipsOfEndpoint . ToDictionary ( relationship => relationship ,
247257 _nonPrimaryDocumentTypeFactory . GetForRelationshipResponse ) ;
248258
249259 return new RelationshipResponseMetadata ( documentTypesByRelationship . AsReadOnly ( ) , successStatusCodes , errorStatusCodes ) ;
250260 }
251261
252- private static EmptyRelationshipResponseMetadata GetEmptyRelationshipResponseMetadata ( IReadOnlyCollection < RelationshipAttribute > relationships ,
253- bool ignoreHasOneRelationships , ReadOnlyCollection < HttpStatusCode > successStatusCodes , ReadOnlyCollection < HttpStatusCode > errorStatusCodes )
262+ private static EmptyRelationshipResponseMetadata GetEmptyRelationshipResponseMetadata ( JsonApiEndpoints endpoint ,
263+ IReadOnlyCollection < RelationshipAttribute > relationships , ReadOnlyCollection < HttpStatusCode > successStatusCodes ,
264+ ReadOnlyCollection < HttpStatusCode > errorStatusCodes )
254265 {
255- IReadOnlyCollection < RelationshipAttribute > relationshipsOfEndpoint =
256- ignoreHasOneRelationships ? relationships . OfType < HasManyAttribute > ( ) . ToList ( ) . AsReadOnly ( ) : relationships ;
266+ IEnumerable < RelationshipAttribute > relationshipsOfEndpoint = FilterRelationshipsForEndpoint ( endpoint , relationships ) ;
257267
258- return new EmptyRelationshipResponseMetadata ( relationshipsOfEndpoint , successStatusCodes , errorStatusCodes ) ;
268+ return new EmptyRelationshipResponseMetadata ( relationshipsOfEndpoint . ToArray ( ) . AsReadOnly ( ) , successStatusCodes , errorStatusCodes ) ;
259269 }
260270
261271 private JsonApiEndpointMetadata GetCustomMetadata ( ActionDescriptor descriptor , ResourceType controllerResourceType )
@@ -281,19 +291,18 @@ private JsonApiEndpointMetadata GetCustomMetadata(ActionDescriptor descriptor, R
281291 ConsistencyGuard . ThrowIf ( actionMethod == null ) ;
282292
283293 HashSet < string > httpMethods = actionMethod . GetCustomAttributes < HttpMethodAttribute > ( true ) . SelectMany ( httpMethod => httpMethod . HttpMethods ) . ToHashSet ( ) ;
284- bool skipHasOneAtRelationshipEndpoint = httpMethods . Any ( httpMethod => HttpMethods . IsPost ( httpMethod ) || HttpMethods . IsDelete ( httpMethod ) ) ;
285294
286295 IJsonApiRequestMetadata ? requestMetadata = GetCustomRequestMetadata ( descriptor , controllerResourceType , hasParameterForId ,
287- hasParameterForRelationshipName , skipHasOneAtRelationshipEndpoint ) ;
296+ hasParameterForRelationshipName , httpMethods ) ;
288297
289298 IJsonApiResponseMetadata ? responseMetadata = GetCustomResponseMetadata ( descriptor , controllerResourceType , hasParameterForRelationshipName ,
290- hasRelationshipsInRoute , skipHasOneAtRelationshipEndpoint ) ;
299+ hasRelationshipsInRoute , httpMethods ) ;
291300
292301 return new JsonApiEndpointMetadata ( requestMetadata , responseMetadata ) ;
293302 }
294303
295304 private IJsonApiRequestMetadata ? GetCustomRequestMetadata ( ActionDescriptor descriptor , ResourceType controllerResourceType , bool hasParameterForId ,
296- bool hasParameterForRelationshipName , bool skipHasOneAtRelationshipEndpoint )
305+ bool hasParameterForRelationshipName , HashSet < string > httpMethods )
297306 {
298307 ConsumesAttribute ? consumes = descriptor . FilterDescriptors . Select ( filter => filter . Filter ) . OfType < ConsumesAttribute > ( ) . FirstOrDefault ( ) ;
299308
@@ -310,14 +319,19 @@ private JsonApiEndpointMetadata GetCustomMetadata(ActionDescriptor descriptor, R
310319 : GetPostResourceRequestMetadata ( primaryResourceType . ClrType ) ;
311320 }
312321
313- return GetRelationshipRequestMetadata ( primaryResourceType . Relationships , skipHasOneAtRelationshipEndpoint ) ;
322+ JsonApiEndpoints ? relationshipEndpoint = InferRelationshipEndpoint ( httpMethods ) ;
323+
324+ if ( relationshipEndpoint != null )
325+ {
326+ return GetRelationshipRequestMetadata ( relationshipEndpoint . Value , primaryResourceType . Relationships ) ;
327+ }
314328 }
315329
316330 return null ;
317331 }
318332
319333 private IJsonApiResponseMetadata ? GetCustomResponseMetadata ( ActionDescriptor descriptor , ResourceType controllerResourceType ,
320- bool hasParameterForRelationshipName , bool hasRelationshipsInRoute , bool skipHasOneAtRelationshipEndpoint )
334+ bool hasParameterForRelationshipName , bool hasRelationshipsInRoute , HashSet < string > httpMethods )
321335 {
322336 ResourceType ? successResponseBodyType = null ;
323337 bool isResponseBodyCollection = false ;
@@ -363,10 +377,43 @@ private JsonApiEndpointMetadata GetCustomMetadata(ActionDescriptor descriptor, R
363377
364378 if ( hasParameterForRelationshipName && hasRelationshipsInRoute )
365379 {
366- return successResponseBodyType != null
367- ? GetRelationshipResponseMetadata ( primaryResourceType . Relationships , skipHasOneAtRelationshipEndpoint , successStatusCodes , errorStatusCodes )
368- : GetEmptyRelationshipResponseMetadata ( primaryResourceType . Relationships , skipHasOneAtRelationshipEndpoint , successStatusCodes ,
380+ if ( successResponseBodyType != null )
381+ {
382+ return GetRelationshipResponseMetadata ( primaryResourceType . Relationships , successStatusCodes , errorStatusCodes ) ;
383+ }
384+
385+ JsonApiEndpoints ? relationshipEndpoint = InferRelationshipEndpoint ( httpMethods ) ;
386+
387+ if ( relationshipEndpoint != null )
388+ {
389+ return GetEmptyRelationshipResponseMetadata ( relationshipEndpoint . Value , primaryResourceType . Relationships , successStatusCodes ,
369390 errorStatusCodes ) ;
391+ }
392+ }
393+
394+ return null ;
395+ }
396+
397+ private static JsonApiEndpoints ? InferRelationshipEndpoint ( HashSet < string > httpMethods )
398+ {
399+ if ( httpMethods . All ( HttpMethods . IsPost ) )
400+ {
401+ return JsonApiEndpoints . PostRelationship ;
402+ }
403+
404+ if ( httpMethods . All ( HttpMethods . IsPatch ) )
405+ {
406+ return JsonApiEndpoints . PatchRelationship ;
407+ }
408+
409+ if ( httpMethods . All ( HttpMethods . IsDelete ) )
410+ {
411+ return JsonApiEndpoints . DeleteRelationship ;
412+ }
413+
414+ if ( httpMethods . All ( method => HttpMethods . IsGet ( method ) || HttpMethods . IsHead ( method ) ) )
415+ {
416+ return JsonApiEndpoints . GetRelationship ;
370417 }
371418
372419 return null ;
0 commit comments