1
+ using System . Net ;
1
2
using System . Reflection ;
2
3
using JsonApiDotNetCore . Configuration ;
3
4
using JsonApiDotNetCore . Controllers ;
4
5
using JsonApiDotNetCore . Middleware ;
5
6
using JsonApiDotNetCore . OpenApi . JsonApiMetadata ;
7
+ using JsonApiDotNetCore . OpenApi . JsonApiObjects . Documents ;
6
8
using JsonApiDotNetCore . Resources . Annotations ;
7
- using Microsoft . AspNetCore . Http ;
8
9
using Microsoft . AspNetCore . Mvc ;
9
10
using Microsoft . AspNetCore . Mvc . ApplicationModels ;
10
11
@@ -17,14 +18,17 @@ internal sealed class OpenApiEndpointConvention : IActionModelConvention
17
18
{
18
19
private readonly IControllerResourceMapping _controllerResourceMapping ;
19
20
private readonly EndpointResolver _endpointResolver ;
21
+ private readonly IJsonApiOptions _options ;
20
22
21
- public OpenApiEndpointConvention ( IControllerResourceMapping controllerResourceMapping , EndpointResolver endpointResolver )
23
+ public OpenApiEndpointConvention ( IControllerResourceMapping controllerResourceMapping , EndpointResolver endpointResolver , IJsonApiOptions options )
22
24
{
23
25
ArgumentGuard . NotNull ( controllerResourceMapping ) ;
24
26
ArgumentGuard . NotNull ( endpointResolver ) ;
27
+ ArgumentGuard . NotNull ( options ) ;
25
28
26
29
_controllerResourceMapping = controllerResourceMapping ;
27
30
_endpointResolver = endpointResolver ;
31
+ _options = options ;
28
32
}
29
33
30
34
public void Apply ( ActionModel action )
@@ -41,25 +45,25 @@ public void Apply(ActionModel action)
41
45
return ;
42
46
}
43
47
44
- if ( ShouldSuppressEndpoint ( endpoint . Value , action . Controller . ControllerType ) )
48
+ ResourceType ? resourceType = _controllerResourceMapping . GetResourceTypeForController ( action . Controller . ControllerType ) ;
49
+
50
+ if ( resourceType == null )
51
+ {
52
+ throw new UnreachableCodeException ( ) ;
53
+ }
54
+
55
+ if ( ShouldSuppressEndpoint ( endpoint . Value , resourceType ) )
45
56
{
46
57
action . ApiExplorer . IsVisible = false ;
47
58
return ;
48
59
}
49
60
50
- SetResponseMetadata ( action , endpoint . Value ) ;
61
+ SetResponseMetadata ( action , endpoint . Value , resourceType ) ;
51
62
SetRequestMetadata ( action , endpoint . Value ) ;
52
63
}
53
64
54
- private bool ShouldSuppressEndpoint ( JsonApiEndpoint endpoint , Type controllerType )
65
+ private bool ShouldSuppressEndpoint ( JsonApiEndpoint endpoint , ResourceType resourceType )
55
66
{
56
- ResourceType ? resourceType = _controllerResourceMapping . GetResourceTypeForController ( controllerType ) ;
57
-
58
- if ( resourceType == null )
59
- {
60
- throw new UnreachableCodeException ( ) ;
61
- }
62
-
63
67
if ( ! IsEndpointAvailable ( endpoint , resourceType ) )
64
68
{
65
69
return true ;
@@ -123,49 +127,84 @@ private static bool IsSecondaryOrRelationshipEndpoint(JsonApiEndpoint endpoint)
123
127
JsonApiEndpoint . PatchRelationship or JsonApiEndpoint . DeleteRelationship ;
124
128
}
125
129
126
- private static void SetResponseMetadata ( ActionModel action , JsonApiEndpoint endpoint )
130
+ private void SetResponseMetadata ( ActionModel action , JsonApiEndpoint endpoint , ResourceType resourceType )
127
131
{
128
- foreach ( int statusCode in GetStatusCodesForEndpoint ( endpoint ) )
132
+ action . Filters . Add ( new ProducesAttribute ( HeaderConstants . MediaType ) ) ;
133
+
134
+ foreach ( HttpStatusCode statusCode in GetSuccessStatusCodesForEndpoint ( endpoint ) )
129
135
{
130
- action . Filters . Add ( new ProducesResponseTypeAttribute ( statusCode ) ) ;
136
+ // The return type is set later by JsonApiActionDescriptorCollectionProvider.
137
+ action . Filters . Add ( new ProducesResponseTypeAttribute ( ( int ) statusCode ) ) ;
138
+ }
131
139
132
- switch ( endpoint )
133
- {
134
- case JsonApiEndpoint . GetCollection when statusCode == StatusCodes . Status200OK :
135
- case JsonApiEndpoint . Post when statusCode == StatusCodes . Status201Created :
136
- case JsonApiEndpoint . Patch when statusCode == StatusCodes . Status200OK :
137
- case JsonApiEndpoint . GetSingle when statusCode == StatusCodes . Status200OK :
138
- case JsonApiEndpoint . GetSecondary when statusCode == StatusCodes . Status200OK :
139
- case JsonApiEndpoint . GetRelationship when statusCode == StatusCodes . Status200OK :
140
- {
141
- action . Filters . Add ( new ProducesAttribute ( HeaderConstants . MediaType ) ) ;
142
- break ;
143
- }
144
- }
140
+ foreach ( HttpStatusCode statusCode in GetErrorStatusCodesForEndpoint ( endpoint , resourceType ) )
141
+ {
142
+ action . Filters . Add ( new ProducesResponseTypeAttribute ( typeof ( ErrorResponseDocument ) , ( int ) statusCode ) ) ;
145
143
}
146
144
}
147
145
148
- private static IEnumerable < int > GetStatusCodesForEndpoint ( JsonApiEndpoint endpoint )
146
+ private static IEnumerable < HttpStatusCode > GetSuccessStatusCodesForEndpoint ( JsonApiEndpoint endpoint )
149
147
{
150
148
return endpoint switch
151
149
{
152
- JsonApiEndpoint . GetCollection or JsonApiEndpoint . GetSingle or JsonApiEndpoint . GetSecondary or JsonApiEndpoint . GetRelationship =>
150
+ JsonApiEndpoint . GetCollection or JsonApiEndpoint . GetSingle or JsonApiEndpoint . GetSecondary or JsonApiEndpoint . GetRelationship
151
+ => [ HttpStatusCode . OK ] ,
152
+ JsonApiEndpoint . Post =>
153
+ [
154
+ HttpStatusCode . Created ,
155
+ HttpStatusCode . NoContent
156
+ ] ,
157
+ JsonApiEndpoint . Patch =>
158
+ [
159
+ HttpStatusCode . OK ,
160
+ HttpStatusCode . NoContent
161
+ ] ,
162
+ JsonApiEndpoint . Delete or JsonApiEndpoint . PostRelationship or JsonApiEndpoint . PatchRelationship or JsonApiEndpoint . DeleteRelationship =>
163
+ [
164
+ HttpStatusCode . NoContent
165
+ ] ,
166
+ _ => throw new UnreachableCodeException ( )
167
+ } ;
168
+ }
169
+
170
+ private IEnumerable < HttpStatusCode > GetErrorStatusCodesForEndpoint ( JsonApiEndpoint endpoint , ResourceType resourceType )
171
+ {
172
+ ClientIdGenerationMode clientIdGeneration = resourceType . ClientIdGeneration ?? _options . ClientIdGeneration ;
173
+
174
+ return endpoint switch
175
+ {
176
+ JsonApiEndpoint . GetCollection => [ HttpStatusCode . BadRequest ] ,
177
+ JsonApiEndpoint . GetSingle or JsonApiEndpoint . GetSecondary or JsonApiEndpoint . GetRelationship =>
178
+ [
179
+ HttpStatusCode . BadRequest ,
180
+ HttpStatusCode . NotFound
181
+ ] ,
182
+ JsonApiEndpoint . Post when clientIdGeneration == ClientIdGenerationMode . Forbidden =>
153
183
[
154
- StatusCodes . Status200OK
184
+ HttpStatusCode . BadRequest ,
185
+ HttpStatusCode . Forbidden ,
186
+ HttpStatusCode . Conflict ,
187
+ HttpStatusCode . UnprocessableEntity
155
188
] ,
156
189
JsonApiEndpoint . Post =>
157
190
[
158
- StatusCodes . Status201Created ,
159
- StatusCodes . Status204NoContent
191
+ HttpStatusCode . BadRequest ,
192
+ HttpStatusCode . Conflict ,
193
+ HttpStatusCode . UnprocessableEntity
160
194
] ,
161
195
JsonApiEndpoint . Patch =>
162
196
[
163
- StatusCodes . Status200OK ,
164
- StatusCodes . Status204NoContent
197
+ HttpStatusCode . BadRequest ,
198
+ HttpStatusCode . NotFound ,
199
+ HttpStatusCode . Conflict ,
200
+ HttpStatusCode . UnprocessableEntity
165
201
] ,
166
- JsonApiEndpoint . Delete or JsonApiEndpoint . PostRelationship or JsonApiEndpoint . PatchRelationship or JsonApiEndpoint . DeleteRelationship => new [ ]
202
+ JsonApiEndpoint . Delete => [ HttpStatusCode . NotFound ] ,
203
+ JsonApiEndpoint . PostRelationship or JsonApiEndpoint . PatchRelationship or JsonApiEndpoint . DeleteRelationship => new [ ]
167
204
{
168
- StatusCodes . Status204NoContent
205
+ HttpStatusCode . BadRequest ,
206
+ HttpStatusCode . NotFound ,
207
+ HttpStatusCode . Conflict
169
208
} ,
170
209
_ => throw new UnreachableCodeException ( )
171
210
} ;
0 commit comments