Skip to content

Commit ad07854

Browse files
JSparshottO2baywet
andauthored
fix: ignore default response when finding media types. (#6414)
* ignore default response when finding media types. * Adding tests and extracting extension method for semantic usage * Add changelog line --------- Co-authored-by: Vincent Biret <[email protected]>
1 parent 9cfee75 commit ad07854

File tree

4 files changed

+79
-3
lines changed

4 files changed

+79
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
### Changed
1515

1616
- Fixed a bug where Dart properties casing would change for serialization.
17+
- Fixed a bug where default response definitions were being considered for Media Type selection [#6413](https://github.com/microsoft/kiota/issues/6413)
1718

1819
## [1.25.1] - 2025-04-03
1920

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Linq;
5+
using Kiota.Builder.CodeDOM;
6+
using Microsoft.OpenApi.Models;
7+
using Microsoft.OpenApi.Models.Interfaces;
8+
9+
namespace Kiota.Builder.Extensions;
10+
public static class OpenApiResponsesExtensions
11+
{
12+
private static readonly HashSet<string> ignorableStatusCodesForMediaTypes = new([
13+
..Enumerable.Range(400, 599).Select(static x => x.ToString(CultureInfo.InvariantCulture)),
14+
CodeMethod.ErrorMappingClientRange,
15+
CodeMethod.ErrorMappingServerRange,
16+
"default"]);
17+
18+
public static IEnumerable<KeyValuePair<string, IOpenApiResponse>> WhereValidForMediaTypeSelection(this OpenApiResponses responses)
19+
=> responses.Where(static x => !ignorableStatusCodesForMediaTypes.Contains(x.Key) && x.Value.Content is not null);
20+
}

src/Kiota.Builder/KiotaBuilder.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ openApiExtension is OpenApiPrimaryErrorMessageExtension primaryErrorMessageExten
12331233
}
12341234
private const string RequestBodyPlainTextContentType = "text/plain";
12351235
private const string RequestBodyOctetStreamContentType = "application/octet-stream";
1236+
private const string DefaultResponseIndicator = "default";
12361237
private static readonly HashSet<string> redirectStatusCodes = new(StringComparer.OrdinalIgnoreCase) { "301", "302", "303", "307" };
12371238
private static readonly HashSet<string> noContentStatusCodes = new(redirectStatusCodes, StringComparer.OrdinalIgnoreCase) { "201", "202", "204", "205", "304" };
12381239
private static readonly HashSet<string> errorStatusCodes = new(Enumerable.Range(400, 599).Select(static x => x.ToString(CultureInfo.InvariantCulture))
@@ -1247,7 +1248,7 @@ private void AddErrorMappingsForExecutorMethod(OpenApiUrlTreeNode currentNode, O
12471248
AddErrorMappingToExecutorMethod(currentNode, operation, executorMethod, schema, response.Value, response.Key.ToUpperInvariant());
12481249
}
12491250
}
1250-
if (operation.Responses.TryGetValue("default", out var defaultResponse) && defaultResponse.GetResponseSchema(config.StructuredMimeTypes) is { } errorSchema)
1251+
if (operation.Responses.TryGetValue(DefaultResponseIndicator, out var defaultResponse) && defaultResponse.GetResponseSchema(config.StructuredMimeTypes) is { } errorSchema)
12511252
{
12521253
if (!executorMethod.HasErrorMappingCode(CodeMethod.ErrorMappingClientRange))
12531254
AddErrorMappingToExecutorMethod(currentNode, operation, executorMethod, errorSchema, defaultResponse, CodeMethod.ErrorMappingClientRange);
@@ -1447,12 +1448,12 @@ private void CreateOperationMethods(OpenApiUrlTreeNode currentNode, NetHttpMetho
14471448
{
14481449
(_, true) => [],
14491450
(null, _) => operation.Responses!
1450-
.Where(static x => !errorStatusCodes.Contains(x.Key) && x.Value.Content is not null)
1451+
.WhereValidForMediaTypeSelection()
14511452
.SelectMany(static x => x.Value.Content!)
14521453
.Select(static x => x.Key) //get the successful non structured media types first, with a default 1 priority
14531454
.Union(config.StructuredMimeTypes.GetAcceptedTypes(
14541455
operation.Responses!
1455-
.Where(static x => errorStatusCodes.Contains(x.Key) && x.Value.Content is not null) // get any structured error ones, with the priority from the configuration
1456+
.WhereValidForMediaTypeSelection()
14561457
.SelectMany(static x => x.Value.Content!) // we can safely ignore unstructured ones as they won't be used in error mappings anyway and the body won't be read
14571458
.Select(static x => x.Key)))
14581459
.Distinct(StringComparer.OrdinalIgnoreCase),
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Linq;
2+
using Kiota.Builder.Extensions;
3+
using Microsoft.OpenApi.Models;
4+
using Xunit;
5+
6+
namespace Kiota.Builder.Tests.Extensions;
7+
public class OpenApiResponsesExtensionsTests
8+
{
9+
[Fact]
10+
public void WhereValidForMediaTypeSelectionReturnsAllIfNothingToFilterOut()
11+
{
12+
var sut = CreateWithStatusCodes(["100", "200", "201", "202", "204", "304", "307"]);
13+
var result = sut.WhereValidForMediaTypeSelection().ToList();
14+
Assert.Equal(7, result.Count);
15+
Assert.Equal(["100", "200", "201", "202", "204", "304", "307"], result.Select(r => r.Key));
16+
}
17+
18+
[Fact]
19+
public void WhereValidForMediaTypeSelectionRemoves400RangeEntries()
20+
{
21+
var sut = CreateWithStatusCodes(["200", "304", "400", "469", "499", "4XX"]);
22+
var result = sut.WhereValidForMediaTypeSelection().ToList();
23+
Assert.Equal(2, result.Count);
24+
Assert.Equal(["200", "304"], result.Select(r => r.Key));
25+
}
26+
27+
[Fact]
28+
public void WhereValidForMediaTypeSelectionRemoves500RangeEntries()
29+
{
30+
var sut = CreateWithStatusCodes(["200", "304", "500", "569", "599", "5XX"]);
31+
var result = sut.WhereValidForMediaTypeSelection().ToList();
32+
Assert.Equal(2, result.Count);
33+
Assert.Equal(["200", "304"], result.Select(r => r.Key));
34+
}
35+
36+
[Fact]
37+
public void WhereValidForMediaTypeSelectionRemovesDefaultEntry()
38+
{
39+
var sut = CreateWithStatusCodes(["200", "304", "default"]);
40+
var result = sut.WhereValidForMediaTypeSelection().ToList();
41+
Assert.Equal(2, result.Count);
42+
Assert.Equal(["200", "304"], result.Select(r => r.Key));
43+
}
44+
45+
private OpenApiResponses CreateWithStatusCodes(string[] statusCodes)
46+
{
47+
var responses = new OpenApiResponses();
48+
foreach (var sc in statusCodes)
49+
{
50+
responses.Add(sc, new OpenApiResponse());
51+
}
52+
return responses;
53+
}
54+
}

0 commit comments

Comments
 (0)