Skip to content

Commit 32ec618

Browse files
Chris Martinezcommonsensesoftware
Chris Martinez
authored andcommitted
Support IsRequired and DefaultValue added to ApiParameterDescription. Resolves #414.
1 parent 4342f09 commit 32ec618

File tree

6 files changed

+110
-149
lines changed

6 files changed

+110
-149
lines changed

samples/aspnetcore/SwaggerODataSample/SwaggerDefaultValues.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,18 @@ public void Apply( Operation operation, OperationFilterContext context )
2828
foreach ( var parameter in operation.Parameters.OfType<NonBodyParameter>() )
2929
{
3030
var description = context.ApiDescription.ParameterDescriptions.First( p => p.Name == parameter.Name );
31-
var routeInfo = description.RouteInfo;
3231

3332
if ( parameter.Description == null )
3433
{
3534
parameter.Description = description.ModelMetadata?.Description;
3635
}
3736

38-
if ( routeInfo == null )
39-
{
40-
continue;
41-
}
42-
4337
if ( parameter.Default == null )
4438
{
45-
parameter.Default = routeInfo.DefaultValue;
39+
parameter.Default = description.DefaultValue;
4640
}
4741

48-
parameter.Required |= !routeInfo.IsOptional;
42+
parameter.Required |= description.IsRequired;
4943
}
5044
}
5145
}

samples/aspnetcore/SwaggerSample/SwaggerDefaultValues.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,18 @@ public void Apply( Operation operation, OperationFilterContext context )
2828
foreach ( var parameter in operation.Parameters.OfType<NonBodyParameter>() )
2929
{
3030
var description = context.ApiDescription.ParameterDescriptions.First( p => p.Name == parameter.Name );
31-
var routeInfo = description.RouteInfo;
3231

3332
if ( parameter.Description == null )
3433
{
3534
parameter.Description = description.ModelMetadata?.Description;
3635
}
3736

38-
if ( routeInfo == null )
39-
{
40-
continue;
41-
}
42-
4337
if ( parameter.Default == null )
4438
{
45-
parameter.Default = routeInfo.DefaultValue;
39+
parameter.Default = description.DefaultValue;
4640
}
4741

48-
parameter.Required |= !routeInfo.IsOptional;
42+
parameter.Required |= description.IsRequired;
4943
}
5044
}
5145
}

src/Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer/ApiVersionParameterDescriptionContext.cs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
namespace Microsoft.AspNetCore.Mvc.ApiExplorer
22
{
33
using Microsoft.AspNetCore.Mvc.Abstractions;
4-
using Microsoft.AspNetCore.Mvc.ApplicationModels;
54
using Microsoft.AspNetCore.Mvc.ModelBinding;
65
using Microsoft.AspNetCore.Mvc.Routing;
76
using Microsoft.AspNetCore.Mvc.Versioning;
@@ -158,7 +157,7 @@ protected virtual void AddHeader( string name )
158157
}
159158

160159
/// <summary>
161-
/// Adds the description for an API version expressed as a header.
160+
/// Adds the description for an API version expressed as a route parameter in a URL segment.
162161
/// </summary>
163162
protected virtual void UpdateUrlSegment()
164163
{
@@ -175,10 +174,22 @@ where constraints.OfType<ApiVersionRouteConstraint>().Any()
175174
return;
176175
}
177176

177+
parameter.IsRequired = true;
178+
parameter.DefaultValue = ApiVersion.ToString();
178179
parameter.ModelMetadata = ModelMetadata;
179180
parameter.Type = ModelMetadata.ModelType;
180181
parameter.RouteInfo.IsOptional = false;
181-
parameter.RouteInfo.DefaultValue = ApiVersion.ToString();
182+
parameter.RouteInfo.DefaultValue = parameter.DefaultValue;
183+
184+
if ( parameter.ParameterDescriptor == null )
185+
{
186+
parameter.ParameterDescriptor = new ParameterDescriptor()
187+
{
188+
Name = parameter.Name,
189+
ParameterType = typeof( ApiVersion ),
190+
};
191+
}
192+
182193
RemoveAllParametersExcept( parameter );
183194
}
184195

@@ -239,17 +250,29 @@ ApiParameterDescription NewApiVersionParameter( string name, BindingSource sourc
239250

240251
var parameter = new ApiParameterDescription()
241252
{
242-
Name = name,
253+
DefaultValue = ApiVersion.ToString(),
254+
IsRequired = !optional,
243255
ModelMetadata = ModelMetadata,
244-
Source = source,
245-
RouteInfo = new ApiParameterRouteInfo()
256+
Name = name,
257+
ParameterDescriptor = new ParameterDescriptor()
246258
{
247-
DefaultValue = ApiVersion.ToString(),
248-
IsOptional = optional,
259+
Name = name,
260+
ParameterType = typeof( ApiVersion ),
249261
},
262+
Source = source,
250263
Type = ModelMetadata.ModelType,
251264
};
252265

266+
if ( source == BindingSource.Path )
267+
{
268+
parameter.IsRequired = true;
269+
parameter.RouteInfo = new ApiParameterRouteInfo()
270+
{
271+
DefaultValue = ApiVersion.ToString(),
272+
IsOptional = false,
273+
};
274+
}
275+
253276
optional = true;
254277
parameters.Add( parameter );
255278

@@ -258,7 +281,7 @@ ApiParameterDescription NewApiVersionParameter( string name, BindingSource sourc
258281

259282
void RemoveAllParametersExcept( ApiParameterDescription parameter )
260283
{
261-
// note: in a scenario where multiple api version parameters are allowed, we can remove all other parameters because
284+
// in a scenario where multiple api version parameters are allowed, we can remove all other parameters because
262285
// the api version must be specified in the path. this will avoid unwanted, duplicate api version parameters
263286
var collections = new ICollection<ApiParameterDescription>[] { ApiDescription.ParameterDescriptions, parameters };
264287

src/Microsoft.AspNetCore.OData.Versioning.ApiExplorer/AspNet.OData/Builder/ODataValidationSettingsConvention.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,15 @@ public virtual void ApplyTo( ApiDescription apiDescription )
9494

9595
return new ApiParameterDescription()
9696
{
97+
DefaultValue = defaultValue,
98+
IsRequired = false,
9799
ModelMetadata = new ODataQueryOptionModelMetadata( Settings.ModelMetadataProvider, type, description ),
98100
Name = name,
99101
ParameterDescriptor = new ParameterDescriptor()
100102
{
101103
Name = name,
102104
ParameterType = type,
103105
},
104-
RouteInfo = new ApiParameterRouteInfo()
105-
{
106-
DefaultValue = defaultValue,
107-
IsOptional = true,
108-
},
109106
Source = Query,
110107
Type = type,
111108
};

test/Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer.Tests/ApiVersionParameterDescriptionContextTest.cs

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ public void add_parameter_should_add_descriptor_for_query_parameter()
2121
// arrange
2222
var version = new ApiVersion( 1, 0 );
2323
var description = NewApiDescription( version );
24-
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) );
24+
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) ).Object;
2525
var options = new ApiExplorerOptions()
2626
{
2727
DefaultApiVersion = version,
2828
ApiVersionParameterSource = new QueryStringApiVersionReader()
2929
};
30-
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata.Object, options );
30+
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata, options );
3131

3232
// act
3333
context.AddParameter( "api-version", Query );
@@ -39,12 +39,9 @@ public void add_parameter_should_add_descriptor_for_query_parameter()
3939
Name = "api-version",
4040
ModelMetadata = modelMetadata,
4141
Source = BindingSource.Query,
42-
RouteInfo = new ApiParameterRouteInfo()
43-
{
44-
DefaultValue = "1.0",
45-
IsOptional = false
46-
},
47-
Type = typeof( string )
42+
DefaultValue = (object) "1.0",
43+
IsRequired = true,
44+
Type = typeof( string ),
4845
},
4946
o => o.ExcludingMissingMembers() );
5047
}
@@ -55,13 +52,13 @@ public void add_parameter_should_add_descriptor_for_header()
5552
// arrange
5653
var version = new ApiVersion( 1, 0 );
5754
var description = NewApiDescription( version );
58-
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) );
55+
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) ).Object;
5956
var options = new ApiExplorerOptions()
6057
{
6158
DefaultApiVersion = version,
6259
ApiVersionParameterSource = new HeaderApiVersionReader()
6360
};
64-
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata.Object, options );
61+
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata, options );
6562

6663
// act
6764
context.AddParameter( "api-version", Header );
@@ -73,12 +70,9 @@ public void add_parameter_should_add_descriptor_for_header()
7370
Name = "api-version",
7471
ModelMetadata = modelMetadata,
7572
Source = BindingSource.Header,
76-
RouteInfo = new ApiParameterRouteInfo()
77-
{
78-
DefaultValue = "1.0",
79-
IsOptional = false
80-
},
81-
Type = typeof( string )
73+
DefaultValue = (object) "1.0",
74+
IsRequired = true,
75+
Type = typeof( string ),
8276
},
8377
o => o.ExcludingMissingMembers() );
8478
}
@@ -98,13 +92,13 @@ public void add_parameter_should_add_descriptor_for_path()
9892
};
9993
var version = new ApiVersion( 1, 0 );
10094
var description = NewApiDescription( version, parameter );
101-
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) );
95+
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) ).Object;
10296
var options = new ApiExplorerOptions()
10397
{
10498
DefaultApiVersion = version,
10599
ApiVersionParameterSource = new UrlSegmentApiVersionReader()
106100
};
107-
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata.Object, options );
101+
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata, options );
108102

109103
// act
110104
context.AddParameter( "api-version", Path );
@@ -116,13 +110,15 @@ public void add_parameter_should_add_descriptor_for_path()
116110
Name = "api-version",
117111
ModelMetadata = modelMetadata,
118112
Source = BindingSource.Path,
113+
DefaultValue = (object) "1.0",
114+
IsRequired = true,
119115
RouteInfo = new ApiParameterRouteInfo()
120116
{
121117
DefaultValue = "1.0",
122118
IsOptional = false,
123-
Constraints = parameter.RouteInfo.Constraints
119+
Constraints = parameter.RouteInfo.Constraints,
124120
},
125-
Type = typeof( string )
121+
Type = typeof( string ),
126122
},
127123
o => o.ExcludingMissingMembers() );
128124
}
@@ -161,15 +157,17 @@ public void add_parameter_should_remove_other_descriptors_after_path_parameter_i
161157
new
162158
{
163159
Name = "api-version",
164-
ModelMetadata = modelMetadata,
160+
ModelMetadata = modelMetadata.Object,
165161
Source = BindingSource.Path,
162+
DefaultValue = (object) "1.0",
163+
IsRequired = true,
166164
RouteInfo = new ApiParameterRouteInfo()
167165
{
168166
DefaultValue = "1.0",
169167
IsOptional = false,
170-
Constraints = parameter.RouteInfo.Constraints
168+
Constraints = parameter.RouteInfo.Constraints,
171169
},
172-
Type = typeof( string )
170+
Type = typeof( string ),
173171
},
174172
o => o.ExcludingMissingMembers() );
175173
}
@@ -183,7 +181,7 @@ public void add_parameter_should_not_add_query_parameter_after_path_parameter_ha
183181
Name = "api-version",
184182
RouteInfo = new ApiParameterRouteInfo()
185183
{
186-
Constraints = new IRouteConstraint[] { new ApiVersionRouteConstraint() }
184+
Constraints = new IRouteConstraint[] { new ApiVersionRouteConstraint() },
187185
},
188186
Source = BindingSource.Path
189187
};
@@ -193,7 +191,7 @@ public void add_parameter_should_not_add_query_parameter_after_path_parameter_ha
193191
var options = new ApiExplorerOptions()
194192
{
195193
DefaultApiVersion = version,
196-
ApiVersionParameterSource = Combine( new QueryStringApiVersionReader(), new UrlSegmentApiVersionReader() )
194+
ApiVersionParameterSource = Combine( new QueryStringApiVersionReader(), new UrlSegmentApiVersionReader() ),
197195
};
198196
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata.Object, options );
199197

@@ -218,26 +216,26 @@ public void add_parameter_should_add_descriptor_for_media_type_parameter()
218216
ActionDescriptor = new ActionDescriptor() { Properties = { [typeof( ApiVersionModel )] = new ApiVersionModel( version ) } },
219217
SupportedRequestFormats =
220218
{
221-
new ApiRequestFormat() { MediaType = Json }
219+
new ApiRequestFormat() { MediaType = Json },
222220
},
223221
SupportedResponseTypes =
224222
{
225-
new ApiResponseType()
226-
{
227-
ApiResponseFormats =
223+
new ApiResponseType()
224+
{
225+
ApiResponseFormats =
228226
{
229-
new ApiResponseFormat() { MediaType = Json }
230-
}
231-
}
232-
}
227+
new ApiResponseFormat() { MediaType = Json },
228+
},
229+
},
230+
},
233231
};
234-
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) );
232+
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) ).Object;
235233
var options = new ApiExplorerOptions()
236234
{
237235
DefaultApiVersion = version,
238-
ApiVersionParameterSource = new MediaTypeApiVersionReader()
236+
ApiVersionParameterSource = new MediaTypeApiVersionReader(),
239237
};
240-
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata.Object, options );
238+
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata, options );
241239

242240
// act
243241
context.AddParameter( "v", MediaTypeParameter );
@@ -253,14 +251,14 @@ public void add_parameter_should_add_optional_parameter_when_allowed()
253251
// arrange
254252
var version = new ApiVersion( 1, 0 );
255253
var description = NewApiDescription( version );
256-
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) );
254+
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) ).Object;
257255
var options = new ApiExplorerOptions()
258256
{
259257
DefaultApiVersion = version,
260258
ApiVersionParameterSource = new QueryStringApiVersionReader(),
261-
AssumeDefaultVersionWhenUnspecified = true
259+
AssumeDefaultVersionWhenUnspecified = true,
262260
};
263-
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata.Object, options );
261+
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata, options );
264262

265263
// act
266264
context.AddParameter( "api-version", Query );
@@ -272,12 +270,9 @@ public void add_parameter_should_add_optional_parameter_when_allowed()
272270
Name = "api-version",
273271
ModelMetadata = modelMetadata,
274272
Source = BindingSource.Query,
275-
RouteInfo = new ApiParameterRouteInfo()
276-
{
277-
DefaultValue = "1.0",
278-
IsOptional = true
279-
},
280-
Type = typeof( string )
273+
DefaultValue = (object) "1.0",
274+
IsRequired = false,
275+
Type = typeof( string ),
281276
},
282277
o => o.ExcludingMissingMembers() );
283278
}
@@ -288,21 +283,21 @@ public void add_parameter_should_make_parameters_optional_after_first_parameter(
288283
// arrange
289284
var version = new ApiVersion( 1, 0 );
290285
var description = NewApiDescription( version );
291-
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) );
286+
var modelMetadata = new Mock<ModelMetadata>( ModelMetadataIdentity.ForType( typeof( string ) ) ).Object;
292287
var options = new ApiExplorerOptions()
293288
{
294289
DefaultApiVersion = version,
295290
ApiVersionParameterSource = Combine( new QueryStringApiVersionReader(), new HeaderApiVersionReader() )
296291
};
297-
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata.Object, options );
292+
var context = new ApiVersionParameterDescriptionContext( description, version, modelMetadata, options );
298293

299294
// act
300295
context.AddParameter( "api-version", Query );
301296
context.AddParameter( "api-version", Header );
302297

303298
// assert
304-
description.ParameterDescriptions[0].RouteInfo.IsOptional.Should().BeFalse();
305-
description.ParameterDescriptions[1].RouteInfo.IsOptional.Should().BeTrue();
299+
description.ParameterDescriptions[0].IsRequired.Should().BeTrue();
300+
description.ParameterDescriptions[1].IsRequired.Should().BeFalse();
306301
}
307302

308303
static ApiDescription NewApiDescription( ApiVersion apiVersion, params ApiParameterDescription[] parameters )

0 commit comments

Comments
 (0)