Skip to content

Commit bc530c3

Browse files
committed
Validation using walker and single visitor class
1 parent aebee6f commit bc530c3

File tree

3 files changed

+66
-35
lines changed

3 files changed

+66
-35
lines changed

src/Microsoft.OpenApi/Services/OpenApiValidator.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// Licensed under the MIT license.
33

44
using System.Collections.Generic;
5+
using System.Linq;
56
using Microsoft.OpenApi.Exceptions;
67
using Microsoft.OpenApi.Models;
8+
using Microsoft.OpenApi.Validations;
79

810
namespace Microsoft.OpenApi.Services
911
{
@@ -12,20 +14,34 @@ namespace Microsoft.OpenApi.Services
1214
/// </summary>
1315
public class OpenApiValidator : OpenApiVisitorBase
1416
{
15-
/// <summary>
16-
/// Exceptions related to this validation.
17-
/// </summary>
18-
public List<OpenApiException> Exceptions { get; } = new List<OpenApiException>();
17+
readonly ValidationRuleSet _ruleSet;
18+
readonly ValidationContext _context;
1919

2020
/// <summary>
21-
/// Visit Open API Response element.
21+
/// Create a vistor that will validate an OpenAPIDocument
2222
/// </summary>
23-
/// <param name="response">Response element.</param>
24-
public override void Visit(OpenApiResponse response)
23+
/// <param name="ruleSet"></param>
24+
public OpenApiValidator(ValidationRuleSet ruleSet = null)
25+
{
26+
_ruleSet = ruleSet ?? ValidationRuleSet.DefaultRuleSet;
27+
_context = new ValidationContext(_ruleSet);
28+
}
29+
30+
public override void Visit(OpenApiDocument item) => Validate(item);
31+
public override void Visit(OpenApiInfo item) => Validate(item);
32+
public override void Visit(OpenApiContact item) => Validate(item);
33+
public override void Visit(OpenApiResponse item) => Validate(item);
34+
35+
36+
public IEnumerable<ValidationError> Errors => _context.Errors;
37+
38+
private void Validate<T>(T item)
2539
{
26-
if (string.IsNullOrEmpty(response.Description))
40+
if (item == null) return; // Required fields should be checked by higher level objects
41+
var rules = _ruleSet.Where(r => r.ElementType == typeof(T));
42+
foreach (var rule in rules)
2743
{
28-
Exceptions.Add(new OpenApiException("Response must have a description"));
44+
rule.Evaluate(_context, item);
2945
}
3046
}
3147
}

src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,140 +13,147 @@ namespace Microsoft.OpenApi.Services
1313
public abstract class OpenApiVisitorBase
1414
{
1515
/// <summary>
16-
/// Validates <see cref="OpenApiDocument"/>
16+
/// Visits <see cref="OpenApiDocument"/>
1717
/// </summary>
1818
public virtual void Visit(OpenApiDocument doc)
1919
{
2020
}
2121

2222
/// <summary>
23-
/// Validates <see cref="OpenApiInfo"/>
23+
/// Visits <see cref="OpenApiInfo"/>
2424
/// </summary>
2525
public virtual void Visit(OpenApiInfo info)
2626
{
2727
}
2828

2929
/// <summary>
30-
/// Validates list of <see cref="OpenApiServer"/>
30+
/// Visits <see cref="OpenApiContact"/>
31+
/// </summary>
32+
public virtual void Visit(OpenApiContact contact)
33+
{
34+
}
35+
36+
/// <summary>
37+
/// Visits list of <see cref="OpenApiServer"/>
3138
/// </summary>
3239
public virtual void Visit(IList<OpenApiServer> servers)
3340
{
3441
}
3542

3643
/// <summary>
37-
/// Validates <see cref="OpenApiServer"/>
44+
/// Visits <see cref="OpenApiServer"/>
3845
/// </summary>
3946
public virtual void Visit(OpenApiServer server)
4047
{
4148
}
4249

4350
/// <summary>
44-
/// Validates <see cref="OpenApiPaths"/>
51+
/// Visits <see cref="OpenApiPaths"/>
4552
/// </summary>
4653
public virtual void Visit(OpenApiPaths paths)
4754
{
4855
}
4956

5057
/// <summary>
51-
/// Validates <see cref="OpenApiPathItem"/>
58+
/// Visits <see cref="OpenApiPathItem"/>
5259
/// </summary>
5360
public virtual void Visit(OpenApiPathItem pathItem)
5461
{
5562
}
5663

5764
/// <summary>
58-
/// Validates <see cref="OpenApiServerVariable"/>
65+
/// Visits <see cref="OpenApiServerVariable"/>
5966
/// </summary>
6067
public virtual void Visit(OpenApiServerVariable serverVariable)
6168
{
6269
}
6370

6471
/// <summary>
65-
/// Validates the operations.
72+
/// Visits the operations.
6673
/// </summary>
6774
public virtual void Visit(IDictionary<OperationType, OpenApiOperation> operations)
6875
{
6976
}
7077

7178
/// <summary>
72-
/// Validates <see cref="OpenApiOperation"/>
79+
/// Visits <see cref="OpenApiOperation"/>
7380
/// </summary>
7481
public virtual void Visit(OpenApiOperation operation)
7582
{
7683
}
7784

7885
/// <summary>
79-
/// Validates list of <see cref="OpenApiParameter"/>
86+
/// Visits list of <see cref="OpenApiParameter"/>
8087
/// </summary>
8188
public virtual void Visit(IList<OpenApiParameter> parameters)
8289
{
8390
}
8491

8592
/// <summary>
86-
/// Validates <see cref="OpenApiParameter"/>
93+
/// Visits <see cref="OpenApiParameter"/>
8794
/// </summary>
8895
public virtual void Visit(OpenApiParameter parameter)
8996
{
9097
}
9198

9299
/// <summary>
93-
/// Validates <see cref="OpenApiRequestBody"/>
100+
/// Visits <see cref="OpenApiRequestBody"/>
94101
/// </summary>
95102
public virtual void Visit(OpenApiRequestBody requestBody)
96103
{
97104
}
98105

99106
/// <summary>
100-
/// Validates responses.
107+
/// Visits responses.
101108
/// </summary>
102109
public virtual void Visit(IDictionary<string, OpenApiResponse> responses)
103110
{
104111
}
105112

106113
/// <summary>
107-
/// Validates <see cref="OpenApiResponse"/>
114+
/// Visits <see cref="OpenApiResponse"/>
108115
/// </summary>
109116
public virtual void Visit(OpenApiResponse response)
110117
{
111118
}
112119

113120
/// <summary>
114-
/// Validates media type content.
121+
/// Visits media type content.
115122
/// </summary>
116123
public virtual void Visit(IDictionary<string, OpenApiMediaType> content)
117124
{
118125
}
119126

120127
/// <summary>
121-
/// Validates <see cref="OpenApiMediaType"/>
128+
/// Visits <see cref="OpenApiMediaType"/>
122129
/// </summary>
123130
public virtual void Visit(OpenApiMediaType mediaType)
124131
{
125132
}
126133

127134
/// <summary>
128-
/// Validates the examples.
135+
/// Visits the examples.
129136
/// </summary>
130137
public virtual void Visit(IDictionary<string, OpenApiExample> examples)
131138
{
132139
}
133140

134141
/// <summary>
135-
/// Validates <see cref="OpenApiSchema"/>
142+
/// Visits <see cref="OpenApiSchema"/>
136143
/// </summary>
137144
public virtual void Visit(OpenApiSchema schema)
138145
{
139146
}
140147

141148
/// <summary>
142-
/// Validates the links.
149+
/// Visits the links.
143150
/// </summary>
144151
public virtual void Visit(IDictionary<string, OpenApiLink> links)
145152
{
146153
}
147154

148155
/// <summary>
149-
/// Validates <see cref="OpenApiLink"/>
156+
/// Visits <see cref="OpenApiLink"/>
150157
/// </summary>
151158
public virtual void Visit(OpenApiLink link)
152159
{

test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33

4+
using System;
45
using System.Collections.Generic;
56
using FluentAssertions;
67
using Microsoft.OpenApi.Exceptions;
78
using Microsoft.OpenApi.Models;
9+
using Microsoft.OpenApi.Properties;
810
using Microsoft.OpenApi.Services;
11+
using Microsoft.OpenApi.Validations;
912
using Xunit;
1013

1114
namespace Microsoft.OpenApi.Tests.Services
@@ -17,7 +20,11 @@ public class OpenApiValidatorTests
1720
public void ResponseMustHaveADescription()
1821
{
1922
var openApiDocument = new OpenApiDocument();
20-
23+
openApiDocument.Info = new OpenApiInfo()
24+
{
25+
Title = "foo",
26+
Version = "1.2.2"
27+
};
2128
openApiDocument.Paths.Add(
2229
"/test",
2330
new OpenApiPathItem
@@ -38,11 +45,12 @@ public void ResponseMustHaveADescription()
3845
var walker = new OpenApiWalker(validator);
3946
walker.Walk(openApiDocument);
4047

41-
validator.Exceptions.ShouldBeEquivalentTo(
42-
new List<OpenApiException>
43-
{
44-
new OpenApiException("Response must have a description")
45-
});
48+
validator.Errors.ShouldBeEquivalentTo(
49+
new List<ValidationError>
50+
{
51+
new ValidationError(ErrorReason.Required, "#/description",
52+
String.Format(SRResource.Validation_FieldIsRequired, "description", "response"))
53+
});
4654
}
4755
}
4856
}

0 commit comments

Comments
 (0)