Skip to content

Commit a28f5dd

Browse files
authored
Merge pull request microsoft#524 from DCollart/feature/add_validator_for_path_parameters_not_present_in_path
Feature/add validator for path parameters not present in path
2 parents cc0357a + 3f685ef commit a28f5dd

File tree

4 files changed

+102
-7
lines changed

4 files changed

+102
-7
lines changed

src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,22 @@ public static class OpenApiParameterRules
9696
context.Exit();
9797
});
9898

99+
/// <summary>
100+
/// Validate that a path parameter should always appear in the path
101+
/// </summary>
102+
public static ValidationRule<OpenApiParameter> PathParameterShouldBeInThePath =>
103+
new ValidationRule<OpenApiParameter>(
104+
(context, parameter) =>
105+
{
106+
if (parameter.In == ParameterLocation.Path && !context.PathString.Contains("{" + parameter.Name + "}"))
107+
{
108+
context.Enter("in");
109+
context.CreateError(
110+
nameof(PathParameterShouldBeInThePath),
111+
$"Declared path parameter \"{parameter.Name}\" needs to be defined as a path parameter at either the path or operation level");
112+
context.Exit();
113+
}
114+
});
99115
// add more rule.
100116
}
101117
}

test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,7 @@ namespace Microsoft.OpenApi.Validations.Rules
11681168
{
11691169
public static Microsoft.OpenApi.Validations.ValidationRule<Microsoft.OpenApi.Models.OpenApiParameter> ParameterMismatchedDataType { get; }
11701170
public static Microsoft.OpenApi.Validations.ValidationRule<Microsoft.OpenApi.Models.OpenApiParameter> ParameterRequiredFields { get; }
1171+
public static Microsoft.OpenApi.Validations.ValidationRule<Microsoft.OpenApi.Models.OpenApiParameter> PathParameterShouldBeInThePath { get; }
11711172
public static Microsoft.OpenApi.Validations.ValidationRule<Microsoft.OpenApi.Models.OpenApiParameter> RequiredMustBeTrueWhenInIsPath { get; }
11721173
}
11731174
[Microsoft.OpenApi.Validations.Rules.OpenApiRule]

test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,11 @@ public void ValidateRequiredIsTrueWhenInIsPathInParameter()
4848
};
4949

5050
// Act
51-
var errors = parameter.Validate(ValidationRuleSet.GetDefaultRuleSet());
52-
51+
var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
52+
validator.Enter("{name}");
53+
var walker = new OpenApiWalker(validator);
54+
walker.Walk(parameter);
55+
var errors = validator.Errors;
5356
// Assert
5457
errors.Should().NotBeEmpty();
5558
errors.Select(e => e.Message).Should().BeEquivalentTo(new[]
@@ -77,6 +80,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema()
7780

7881
// Act
7982
var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
83+
validator.Enter("{parameter1}");
8084
var walker = new OpenApiWalker(validator);
8185
walker.Walk(parameter);
8286

@@ -91,7 +95,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema()
9195
});
9296
errors.Select(e => e.Pointer).Should().BeEquivalentTo(new[]
9397
{
94-
"#/example",
98+
"#/{parameter1}/example",
9599
});
96100
}
97101

@@ -150,6 +154,7 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema()
150154

151155
// Act
152156
var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
157+
validator.Enter("{parameter1}");
153158
var walker = new OpenApiWalker(validator);
154159
walker.Walk(parameter);
155160

@@ -168,10 +173,83 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema()
168173
{
169174
// #enum/0 is not an error since the spec allows
170175
// representing an object using a string.
171-
"#/examples/example1/value/y",
172-
"#/examples/example1/value/z",
173-
"#/examples/example2/value"
176+
"#/{parameter1}/examples/example1/value/y",
177+
"#/{parameter1}/examples/example1/value/z",
178+
"#/{parameter1}/examples/example2/value"
174179
});
175180
}
181+
182+
[Fact]
183+
public void PathParameterNotInThePathShouldReturnAnError()
184+
{
185+
// Arrange
186+
IEnumerable<OpenApiError> errors;
187+
188+
var parameter = new OpenApiParameter()
189+
{
190+
Name = "parameter1",
191+
In = ParameterLocation.Path,
192+
Required = true,
193+
Schema = new OpenApiSchema()
194+
{
195+
Type = "string",
196+
}
197+
};
198+
199+
// Act
200+
var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
201+
202+
var walker = new OpenApiWalker(validator);
203+
walker.Walk(parameter);
204+
205+
errors = validator.Errors;
206+
bool result = errors.Any();
207+
208+
// Assert
209+
result.Should().BeTrue();
210+
errors.OfType<OpenApiValidatorError>().Select(e => e.RuleName).Should().BeEquivalentTo(new[]
211+
{
212+
"PathParameterShouldBeInThePath"
213+
});
214+
errors.Select(e => e.Pointer).Should().BeEquivalentTo(new[]
215+
{
216+
"#/in"
217+
});
218+
}
219+
220+
[Fact]
221+
public void PathParameterInThePastShouldBeOk()
222+
{
223+
// Arrange
224+
IEnumerable<OpenApiError> errors;
225+
226+
var parameter = new OpenApiParameter()
227+
{
228+
Name = "parameter1",
229+
In = ParameterLocation.Path,
230+
Required = true,
231+
Schema = new OpenApiSchema()
232+
{
233+
Type = "string",
234+
}
235+
};
236+
237+
// Act
238+
var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet());
239+
validator.Enter("paths");
240+
validator.Enter("/{parameter1}");
241+
validator.Enter("get");
242+
validator.Enter("parameters");
243+
validator.Enter("1");
244+
245+
var walker = new OpenApiWalker(validator);
246+
walker.Walk(parameter);
247+
248+
errors = validator.Errors;
249+
bool result = errors.Any();
250+
251+
// Assert
252+
result.Should().BeFalse();
253+
}
176254
}
177255
}

test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public void DefaultRuleSetPropertyReturnsTheCorrectRules()
4343
Assert.NotEmpty(rules);
4444

4545
// Update the number if you add new default rule(s).
46-
Assert.Equal(20, rules.Count);
46+
Assert.Equal(21, rules.Count);
4747
}
4848
}
4949
}

0 commit comments

Comments
 (0)