Skip to content

Commit 82475e2

Browse files
[OpenAPI] Validate OpenAPI documents
- Validate OpenAPI documents with Microsoft.OpenApi. - Exclude HTTP QUERY endpoints. - Fix incorrect parameter casing. Relates to #63090.
1 parent c103a03 commit 82475e2

6 files changed

+38
-100
lines changed

src/OpenApi/sample/Controllers/TestController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ public class HttpFoo() : HttpMethodAttribute(["FOO"]);
6060

6161
public class RouteParamsContainer
6262
{
63-
[FromRoute]
63+
[FromRoute(Name = "id")]
6464
public int Id { get; set; }
6565

66-
[FromRoute]
66+
[FromRoute(Name = "name")]
6767
[MinLength(5)]
6868
[UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", Justification = "MinLengthAttribute works without reflection on string properties.")]
6969
public string? Name { get; set; }

src/OpenApi/src/Extensions/ApiDescriptionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal static class ApiDescriptionExtensions
2828
"HEAD" => HttpMethod.Head,
2929
"OPTIONS" => HttpMethod.Options,
3030
"TRACE" => HttpMethod.Trace,
31-
"QUERY" => HttpMethod.Query,
31+
"QUERY" => null, // OpenAPI as of 3.1 does not yet support HTTP QUERY
3232
_ => null,
3333
};
3434

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/OpenApiDocumentIntegrationTests.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@ public static TheoryData<string, OpenApiSpecVersion> OpenApiDocuments()
3636
[MemberData(nameof(OpenApiDocuments))]
3737
public async Task VerifyOpenApiDocument(string documentName, OpenApiSpecVersion version)
3838
{
39-
var documentService = fixture.Services.GetRequiredKeyedService<OpenApiDocumentService>(documentName);
40-
var scopedServiceProvider = fixture.Services.CreateScope();
41-
var document = await documentService.GetOpenApiDocumentAsync(scopedServiceProvider.ServiceProvider);
42-
var json = await document.SerializeAsJsonAsync(version);
39+
var json = await GetOpenApiDocument(documentName, version);
4340
var baseSnapshotsDirectory = SkipOnHelixAttribute.OnHelix()
4441
? Path.Combine(Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT"), "Integration", "snapshots")
4542
: "snapshots";
@@ -48,4 +45,32 @@ await Verify(json)
4845
.UseDirectory(outputDirectory)
4946
.UseParameters(documentName);
5047
}
48+
49+
[Theory]
50+
[MemberData(nameof(OpenApiDocuments))]
51+
public async Task OpenApiDocumentIsValid(string documentName, OpenApiSpecVersion version)
52+
{
53+
var json = await GetOpenApiDocument(documentName, version);
54+
55+
var actual = OpenApiDocument.Parse(json, format: "json");
56+
57+
Assert.NotNull(actual);
58+
Assert.NotNull(actual.Document);
59+
Assert.NotNull(actual.Diagnostic);
60+
Assert.NotNull(actual.Diagnostic.Errors);
61+
Assert.Empty(actual.Diagnostic.Errors);
62+
63+
var ruleSet = ValidationRuleSet.GetDefaultRuleSet();
64+
65+
var errors = actual.Document.Validate(ruleSet);
66+
Assert.Empty(errors);
67+
}
68+
69+
private async Task<string> GetOpenApiDocument(string documentName, OpenApiSpecVersion version)
70+
{
71+
var documentService = fixture.Services.GetRequiredKeyedService<OpenApiDocumentService>(documentName);
72+
var scopedServiceProvider = fixture.Services.CreateScope();
73+
var document = await documentService.GetOpenApiDocumentAsync(scopedServiceProvider.ServiceProvider);
74+
return await document.SerializeAsJsonAsync(version);
75+
}
5176
}

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_0/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=controllers.verified.txt

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
],
1313
"parameters": [
1414
{
15-
"name": "Id",
15+
"name": "id",
1616
"in": "path",
1717
"required": true,
1818
"schema": {
@@ -21,7 +21,7 @@
2121
}
2222
},
2323
{
24-
"name": "Name",
24+
"name": "name",
2525
"in": "path",
2626
"required": true,
2727
"schema": {
@@ -124,35 +124,6 @@
124124
}
125125
}
126126
}
127-
},
128-
"/query": {
129-
"query": {
130-
"tags": [
131-
"Test"
132-
],
133-
"responses": {
134-
"200": {
135-
"description": "OK",
136-
"content": {
137-
"text/plain": {
138-
"schema": {
139-
"$ref": "#/components/schemas/CurrentWeather"
140-
}
141-
},
142-
"application/json": {
143-
"schema": {
144-
"$ref": "#/components/schemas/CurrentWeather"
145-
}
146-
},
147-
"text/json": {
148-
"schema": {
149-
"$ref": "#/components/schemas/CurrentWeather"
150-
}
151-
}
152-
}
153-
}
154-
}
155-
}
156127
}
157128
},
158129
"components": {

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApi3_1/OpenApiDocumentIntegrationTests.VerifyOpenApiDocument_documentName=controllers.verified.txt

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
],
1313
"parameters": [
1414
{
15-
"name": "Id",
15+
"name": "id",
1616
"in": "path",
1717
"required": true,
1818
"schema": {
@@ -21,7 +21,7 @@
2121
}
2222
},
2323
{
24-
"name": "Name",
24+
"name": "name",
2525
"in": "path",
2626
"required": true,
2727
"schema": {
@@ -124,35 +124,6 @@
124124
}
125125
}
126126
}
127-
},
128-
"/query": {
129-
"query": {
130-
"tags": [
131-
"Test"
132-
],
133-
"responses": {
134-
"200": {
135-
"description": "OK",
136-
"content": {
137-
"text/plain": {
138-
"schema": {
139-
"$ref": "#/components/schemas/CurrentWeather"
140-
}
141-
},
142-
"application/json": {
143-
"schema": {
144-
"$ref": "#/components/schemas/CurrentWeather"
145-
}
146-
},
147-
"text/json": {
148-
"schema": {
149-
"$ref": "#/components/schemas/CurrentWeather"
150-
}
151-
}
152-
}
153-
}
154-
}
155-
}
156127
}
157128
},
158129
"components": {

src/OpenApi/test/Microsoft.AspNetCore.OpenApi.Tests/Integration/snapshots/OpenApiDocumentLocalizationTests.VerifyOpenApiDocumentIsInvariant.verified.txt

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@
11431143
],
11441144
"parameters": [
11451145
{
1146-
"name": "Id",
1146+
"name": "id",
11471147
"in": "path",
11481148
"required": true,
11491149
"schema": {
@@ -1152,7 +1152,7 @@
11521152
}
11531153
},
11541154
{
1155-
"name": "Name",
1155+
"name": "name",
11561156
"in": "path",
11571157
"required": true,
11581158
"schema": {
@@ -1255,35 +1255,6 @@
12551255
}
12561256
}
12571257
}
1258-
},
1259-
"/query": {
1260-
"query": {
1261-
"tags": [
1262-
"Test"
1263-
],
1264-
"responses": {
1265-
"200": {
1266-
"description": "OK",
1267-
"content": {
1268-
"text/plain": {
1269-
"schema": {
1270-
"$ref": "#/components/schemas/CurrentWeather"
1271-
}
1272-
},
1273-
"application/json": {
1274-
"schema": {
1275-
"$ref": "#/components/schemas/CurrentWeather"
1276-
}
1277-
},
1278-
"text/json": {
1279-
"schema": {
1280-
"$ref": "#/components/schemas/CurrentWeather"
1281-
}
1282-
}
1283-
}
1284-
}
1285-
}
1286-
}
12871258
}
12881259
},
12891260
"components": {

0 commit comments

Comments
 (0)