Skip to content

Commit 87cd4b4

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 d84aec3 commit 87cd4b4

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
@@ -1165,7 +1165,7 @@
11651165
],
11661166
"parameters": [
11671167
{
1168-
"name": "Id",
1168+
"name": "id",
11691169
"in": "path",
11701170
"required": true,
11711171
"schema": {
@@ -1174,7 +1174,7 @@
11741174
}
11751175
},
11761176
{
1177-
"name": "Name",
1177+
"name": "name",
11781178
"in": "path",
11791179
"required": true,
11801180
"schema": {
@@ -1277,35 +1277,6 @@
12771277
}
12781278
}
12791279
}
1280-
},
1281-
"/query": {
1282-
"query": {
1283-
"tags": [
1284-
"Test"
1285-
],
1286-
"responses": {
1287-
"200": {
1288-
"description": "OK",
1289-
"content": {
1290-
"text/plain": {
1291-
"schema": {
1292-
"$ref": "#/components/schemas/CurrentWeather"
1293-
}
1294-
},
1295-
"application/json": {
1296-
"schema": {
1297-
"$ref": "#/components/schemas/CurrentWeather"
1298-
}
1299-
},
1300-
"text/json": {
1301-
"schema": {
1302-
"$ref": "#/components/schemas/CurrentWeather"
1303-
}
1304-
}
1305-
}
1306-
}
1307-
}
1308-
}
13091280
}
13101281
},
13111282
"components": {

0 commit comments

Comments
 (0)