Skip to content

Commit 9fecf94

Browse files
committed
Fix issue Empty tag causes error generating Kiota client #2283
1 parent 5d99cc4 commit 9fecf94

File tree

5 files changed

+109
-6
lines changed

5 files changed

+109
-6
lines changed

src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,26 @@ namespace Microsoft.OpenApi.Reader.V2
1919
/// </summary>
2020
internal static partial class OpenApiV2Deserializer
2121
{
22+
/// <summary>
23+
/// Have a default empty tag we can use to filter out empty tags.
24+
/// </summary>
25+
private static OpenApiTagReference emptyTagReference = new("empty");
2226
private static readonly FixedFieldMap<OpenApiOperation> _operationFixedFields =
2327
new()
2428
{
2529
{
26-
"tags", (o, n, doc) => {
27-
if (n.CreateSimpleList((valueNode, doc) => LoadTagByReference(valueNode.GetScalarValue(), doc), doc) is {Count: > 0} tags)
30+
"tags", (o, n, doc) => {
31+
if (n.CreateSimpleList(
32+
(valueNode, doc) =>
33+
{
34+
var val = valueNode.GetScalarValue();
35+
if (string.IsNullOrEmpty(val))
36+
return emptyTagReference; // Avoid exception on empty tag, we'll remove these from the list further on
37+
return LoadTagByReference(val , doc);
38+
},
39+
doc)
40+
// Filter out empty tags instead of excepting on them
41+
.Where(n => !object.ReferenceEquals(emptyTagReference, n)).ToList() is {Count: > 0} tags)
2842
{
2943
o.Tags = new HashSet<OpenApiTagReference>(tags, OpenApiTagComparer.Instance);
3044
}

src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Linq;
67
using Microsoft.OpenApi.Extensions;
78
using Microsoft.OpenApi.Models;
89
using Microsoft.OpenApi.Models.References;
@@ -16,12 +17,26 @@ namespace Microsoft.OpenApi.Reader.V3
1617
/// </summary>
1718
internal static partial class OpenApiV3Deserializer
1819
{
20+
/// <summary>
21+
/// Have a default empty tag we can use to filter out empty tags.
22+
/// </summary>
23+
private static OpenApiTagReference emptyTagReference = new("empty");
1924
private static readonly FixedFieldMap<OpenApiOperation> _operationFixedFields =
2025
new()
2126
{
2227
{
23-
"tags", (o, n, doc) => {
24-
if (n.CreateSimpleList((valueNode, doc) => LoadTagByReference(valueNode.GetScalarValue(), doc), doc) is {Count: > 0} tags)
28+
"tags", (o, n, doc) => {
29+
if (n.CreateSimpleList(
30+
(valueNode, doc) =>
31+
{
32+
var val = valueNode.GetScalarValue();
33+
if (string.IsNullOrEmpty(val))
34+
return emptyTagReference; // Avoid exception on empty tag, we'll remove these from the list further on
35+
return LoadTagByReference(val , doc);
36+
},
37+
doc)
38+
// Filter out empty tags instead of excepting on them
39+
.Where(n => !object.ReferenceEquals(emptyTagReference, n)).ToList() is {Count: > 0} tags)
2540
{
2641
o.Tags = new HashSet<OpenApiTagReference>(tags, OpenApiTagComparer.Instance);
2742
}

src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using Microsoft.OpenApi.Extensions;
45
using Microsoft.OpenApi.Models;
56
using Microsoft.OpenApi.Models.References;
@@ -13,12 +14,26 @@ namespace Microsoft.OpenApi.Reader.V31
1314
/// </summary>
1415
internal static partial class OpenApiV31Deserializer
1516
{
17+
/// <summary>
18+
/// Have a default empty tag we can use to filter out empty tags.
19+
/// </summary>
20+
private static OpenApiTagReference emptyTagReference = new("empty");
1621
private static readonly FixedFieldMap<OpenApiOperation> _operationFixedFields =
1722
new()
1823
{
1924
{
20-
"tags", (o, n, doc) => {
21-
if (n.CreateSimpleList((valueNode, doc) => LoadTagByReference(valueNode.GetScalarValue(), doc), doc) is {Count: > 0} tags)
25+
"tags", (o, n, doc) => {
26+
if (n.CreateSimpleList(
27+
(valueNode, doc) =>
28+
{
29+
var val = valueNode.GetScalarValue();
30+
if (string.IsNullOrEmpty(val))
31+
return emptyTagReference; // Avoid exception on empty tag, we'll remove these from the list further on
32+
return LoadTagByReference(val , doc);
33+
},
34+
doc)
35+
// Filter out empty tags instead of excepting on them
36+
.Where(n => !object.ReferenceEquals(emptyTagReference, n)).ToList() is {Count: > 0} tags)
2237
{
2338
o.Tags = new HashSet<OpenApiTagReference>(tags, OpenApiTagComparer.Instance);
2439
}

test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,15 @@ public async Task ParseDocumentWith31PropertiesWorks()
570570
await Verifier.Verify(actual);
571571
}
572572

573+
[Fact]
574+
public async Task ParseDocumentWithEmptyTagsWorks()
575+
{
576+
var path = Path.Combine(SampleFolderPath, "documentWithEmptyTags.json");
577+
var doc = (await OpenApiDocument.LoadAsync(path, SettingsFixture.ReaderSettings)).Document;
578+
579+
doc.Paths["/groups"].Operations[HttpMethod.Get].Tags.Should().BeNull("Empty tags are ignored, so we should not have any tags");
580+
}
581+
573582
[Fact]
574583
public void ParseEmptyMemoryStreamThrowsAnArgumentException()
575584
{
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"openapi": "3.1.0",
3+
"info": {
4+
"description": "Groups API",
5+
"title": "Groups",
6+
"version": "1.0"
7+
},
8+
"paths": {
9+
"/groups": {
10+
"get": {
11+
"operationId": "getGroups",
12+
"parameters": [
13+
{
14+
"description": "Zero-based page index (0..N)",
15+
"example": 0,
16+
"in": "query",
17+
"name": "page",
18+
"required": false,
19+
"schema": {
20+
"type": "integer",
21+
"format": "int32",
22+
"default": 0,
23+
"minimum": 0
24+
}
25+
}
26+
],
27+
"responses": {
28+
"200": {
29+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedGroup" } } }
30+
}
31+
},
32+
"tags": [ "" ]
33+
}
34+
}
35+
},
36+
"components": {
37+
"schemas": {
38+
"PaginatedGroup": {
39+
"type": "object",
40+
"properties": {
41+
"number": {
42+
"type": "integer",
43+
"format": "int32",
44+
"description": "The number of the current page."
45+
}
46+
}
47+
}
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)