diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3728f90de8..95917684bb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for enum query parameter types. [#2490](https://github.com/microsoft/kiota/issues/2490)
- Added settings in the vscode extension for: backingStore, additionalData, excludeBackwardCompatible, cleanOutput, clearCache, serializers, deserializers, disabledValidationRules, structuredMimeTypes. [#3355](https://github.com/microsoft/kiota/issues/3355)
- Support for primary error message in PHP [#3276](https://github.com/microsoft/kiota/issues/3276)
+- Added support for multiple content type request bodies. [#3377](https://github.com/microsoft/kiota/issues/3377)
+- Added support for multiple content type responses. [#3377](https://github.com/microsoft/kiota/issues/3377)
- Support for primary error message in Python [#3277](https://github.com/microsoft/kiota/issues/3277)
### Changed
@@ -23,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed a bug where a "models" API path segment in the description would derail generation. [#3400](https://github.com/microsoft/kiota/issues/3400)
- Changes to the configuration of RequestInformation are preserved instead of being overwritten. [#3401](https://github.com/microsoft/kiota/pull/3401).
- Fix bug where import statements in typescript wasn't using import type notation for types that are erased at runtime. [#3190](https://github.com/microsoft/kiota/issues/3190)
+- The structured content type generation parameter now supports prioritization with `q=value` syntax. [#3377](https://github.com/microsoft/kiota/issues/3377)
## [1.7.0] - 2023-10-05
diff --git a/it/csharp/basic/basic.csproj b/it/csharp/basic/basic.csproj
index 9559fd1297..7c4ccede47 100644
--- a/it/csharp/basic/basic.csproj
+++ b/it/csharp/basic/basic.csproj
@@ -10,15 +10,15 @@
-
-
+
+
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/it/go/basic/go.mod b/it/go/basic/go.mod
index 0d5d557d62..fa28d22b72 100644
--- a/it/go/basic/go.mod
+++ b/it/go/basic/go.mod
@@ -3,12 +3,12 @@ module integrationtest
go 1.20
require (
- github.com/microsoft/kiota-abstractions-go v1.2.0
- github.com/microsoft/kiota-http-go v0.16.1
- github.com/microsoft/kiota-serialization-form-go v0.9.0
+ github.com/microsoft/kiota-abstractions-go v1.3.0
+ github.com/microsoft/kiota-http-go v1.1.0
+ github.com/microsoft/kiota-serialization-form-go v1.0.0
github.com/microsoft/kiota-serialization-json-go v1.0.4
github.com/microsoft/kiota-serialization-multipart-go v1.0.0
- github.com/microsoft/kiota-serialization-text-go v0.7.0
+ github.com/microsoft/kiota-serialization-text-go v1.0.0
)
require (
@@ -16,12 +16,13 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/google/uuid v1.3.0 // indirect
+ github.com/google/uuid v1.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/std-uritemplate/std-uritemplate/go v0.0.42 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
- go.opentelemetry.io/otel v1.16.0 // indirect
- go.opentelemetry.io/otel/metric v1.16.0 // indirect
- go.opentelemetry.io/otel/trace v1.16.0 // indirect
+ go.opentelemetry.io/otel v1.19.0 // indirect
+ go.opentelemetry.io/otel/metric v1.19.0 // indirect
+ go.opentelemetry.io/otel/trace v1.19.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/it/go/basic/go.sum b/it/go/basic/go.sum
index 358aa45b1c..351348a3fb 100644
--- a/it/go/basic/go.sum
+++ b/it/go/basic/go.sum
@@ -10,32 +10,50 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
+github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/microsoft/kiota-abstractions-go v1.2.0 h1:lUriJgqdCY/QajwWQOgTCQE9Atywfe2NHhgoTCSXTRE=
github.com/microsoft/kiota-abstractions-go v1.2.0/go.mod h1:RkxyZ5x87Njik7iVeQY9M2wtrrL1MJZcXiI/BxD/82g=
+github.com/microsoft/kiota-abstractions-go v1.3.0 h1:mZTAg+Lf43+hoqTYWT53F/Dg+f0bqtHULnTI/GyiXn8=
+github.com/microsoft/kiota-abstractions-go v1.3.0/go.mod h1:yPSuzNSOIVQSFFe1iT+3Lu5zmis22E8Wg+bkyjhd+pY=
github.com/microsoft/kiota-http-go v0.16.1 h1:5SZbSwHs14Xve5VMQHHz00lwL/kEg3H9rgESAUrXnvw=
github.com/microsoft/kiota-http-go v0.16.1/go.mod h1:pKSaeSaBwh3Zadbnzw3kALEZbCZA1gq7A5PuxwVd/aU=
+github.com/microsoft/kiota-http-go v1.1.0 h1:L5I93EiNtlP/X6YzeTlhjWt7Q1DxzC9CmWSVtX3b0tE=
+github.com/microsoft/kiota-http-go v1.1.0/go.mod h1:zESUM6ovki9LEupqziCbxJ+FAYoF0dFDYZVpOkAfSLc=
github.com/microsoft/kiota-serialization-form-go v0.9.0 h1:ZMyvuxg7z1LmRWJOXr5QuJlwnD/tuNatb+k1KPURBFQ=
github.com/microsoft/kiota-serialization-form-go v0.9.0/go.mod h1:FQqYzIrGX6KUoDOlg+DhDWoGaZoB8AicBYGOsBq0Dw4=
+github.com/microsoft/kiota-serialization-form-go v1.0.0 h1:UNdrkMnLFqUCccQZerKjblsyVgifS11b3WCx+eFEsAI=
+github.com/microsoft/kiota-serialization-form-go v1.0.0/go.mod h1:h4mQOO6KVTNciMF6azi1J9QB19ujSw3ULKcSNyXXOMA=
github.com/microsoft/kiota-serialization-json-go v1.0.4 h1:5TaISWwd2Me8clrK7SqNATo0tv9seOq59y4I5953egQ=
github.com/microsoft/kiota-serialization-json-go v1.0.4/go.mod h1:rM4+FsAY+9AEpBsBzkFFis+b/LZLlNKKewuLwK9Q6Mg=
github.com/microsoft/kiota-serialization-multipart-go v1.0.0 h1:3O5sb5Zj+moLBiJympbXNaeV07K0d46IfuEd5v9+pBs=
github.com/microsoft/kiota-serialization-multipart-go v1.0.0/go.mod h1:yauLeBTpANk4L03XD985akNysG24SnRJGaveZf+p4so=
github.com/microsoft/kiota-serialization-text-go v0.7.0 h1:uayeq8fpDcZgL0zDyLkYZsH6zNnEXKgp+bRWfR5LcxA=
github.com/microsoft/kiota-serialization-text-go v0.7.0/go.mod h1:2su1PTllHCMNkHugmvpYad+AKBXUUGoiNP3xOAJUL7w=
+github.com/microsoft/kiota-serialization-text-go v1.0.0 h1:XOaRhAXy+g8ZVpcq7x7a0jlETWnWrEum0RhmbYrTFnA=
+github.com/microsoft/kiota-serialization-text-go v1.0.0/go.mod h1:sM1/C6ecnQ7IquQOGUrUldaO5wj+9+v7G2W3sQ3fy6M=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/std-uritemplate/std-uritemplate/go v0.0.42 h1:rG+XlE4drkVWs2NLfGS15N+vg+CUcjXElQKvJ0fctlI=
+github.com/std-uritemplate/std-uritemplate/go v0.0.42/go.mod h1:Qov4Ay4U83j37XjgxMYevGJFLbnZ2o9cEOhGufBKgKY=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
+go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
+go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
+go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
+go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
+go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
+go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/it/go/go.mod b/it/go/go.mod
index 2b64da67d0..18a22f9f94 100644
--- a/it/go/go.mod
+++ b/it/go/go.mod
@@ -5,7 +5,7 @@ go 1.20
require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0
github.com/microsoft/kiota-abstractions-go v1.3.0
- github.com/microsoft/kiota-authentication-azure-go v1.0.0
+ github.com/microsoft/kiota-authentication-azure-go v1.0.1
github.com/microsoft/kiota-http-go v1.1.0
github.com/microsoft/kiota-serialization-form-go v1.0.0
github.com/microsoft/kiota-serialization-json-go v1.0.4
diff --git a/it/go/go.sum b/it/go/go.sum
index 72d599f858..71d8e13d2a 100644
--- a/it/go/go.sum
+++ b/it/go/go.sum
@@ -29,6 +29,8 @@ github.com/microsoft/kiota-abstractions-go v1.3.0 h1:mZTAg+Lf43+hoqTYWT53F/Dg+f0
github.com/microsoft/kiota-abstractions-go v1.3.0/go.mod h1:yPSuzNSOIVQSFFe1iT+3Lu5zmis22E8Wg+bkyjhd+pY=
github.com/microsoft/kiota-authentication-azure-go v1.0.0 h1:29FNZZ/4nnCOwFcGWlB/sxPvWz487HA2bXH8jR5k2Rk=
github.com/microsoft/kiota-authentication-azure-go v1.0.0/go.mod h1:rnx3PRlkGdXDcA/0lZQTbBwyYGmc+3POt7HpE/e4jGw=
+github.com/microsoft/kiota-authentication-azure-go v1.0.1 h1:F4HH+2QQHSecQg50gVEZaUcxA8/XxCaC2oOMYv2gTIM=
+github.com/microsoft/kiota-authentication-azure-go v1.0.1/go.mod h1:IbifJeoi+sULI0vjnsWYSmDu5atFo/4FZ6WCoAkPjsc=
github.com/microsoft/kiota-http-go v1.1.0 h1:L5I93EiNtlP/X6YzeTlhjWt7Q1DxzC9CmWSVtX3b0tE=
github.com/microsoft/kiota-http-go v1.1.0/go.mod h1:zESUM6ovki9LEupqziCbxJ+FAYoF0dFDYZVpOkAfSLc=
github.com/microsoft/kiota-serialization-form-go v1.0.0 h1:UNdrkMnLFqUCccQZerKjblsyVgifS11b3WCx+eFEsAI=
diff --git a/src/Kiota.Builder/CodeDOM/CodeMethod.cs b/src/Kiota.Builder/CodeDOM/CodeMethod.cs
index 1d2cc952db..d41be2b74d 100644
--- a/src/Kiota.Builder/CodeDOM/CodeMethod.cs
+++ b/src/Kiota.Builder/CodeDOM/CodeMethod.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using Kiota.Builder.Extensions;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.CodeDOM;
@@ -124,9 +125,15 @@ public HttpMethod? HttpMethod
get; set;
}
public string RequestBodyContentType { get; set; } = string.Empty;
-#pragma warning disable CA2227
- public HashSet AcceptedResponseTypes { get; set; } = new(StringComparer.OrdinalIgnoreCase);
-#pragma warning restore CA2227
+ public IList AcceptedResponseTypes { get; private set; } = new List();
+ public void AddAcceptedResponsesTypes(IEnumerable types)
+ {
+ if (types == null) return;
+ if (AcceptedResponseTypes is List list)
+ list.AddRange(types);
+ }
+ public bool ShouldAddAcceptHeader => AcceptedResponseTypes.Any();
+ public string AcceptHeaderValue => string.Join(", ", AcceptedResponseTypes);
public AccessModifier Access { get; set; } = AccessModifier.Public;
#nullable disable // exposing property is required
private CodeTypeBase returnType;
@@ -302,7 +309,7 @@ public object Clone()
Parent = Parent,
OriginalIndexer = OriginalIndexer,
errorMappings = new(errorMappings),
- AcceptedResponseTypes = new(AcceptedResponseTypes, StringComparer.OrdinalIgnoreCase),
+ AcceptedResponseTypes = new List(AcceptedResponseTypes),
PagingInformation = PagingInformation?.Clone() as PagingInformation,
Documentation = (CodeDocumentation)Documentation.Clone(),
Deprecation = Deprecation,
diff --git a/src/Kiota.Builder/CodeDOM/CodeParameter.cs b/src/Kiota.Builder/CodeDOM/CodeParameter.cs
index 5c5826337b..6f855f8539 100644
--- a/src/Kiota.Builder/CodeDOM/CodeParameter.cs
+++ b/src/Kiota.Builder/CodeDOM/CodeParameter.cs
@@ -46,6 +46,10 @@ public enum CodeParameterKind
/// Configuration for the request to be sent with the headers, query parameters, and middleware options
///
RequestConfiguration,
+ ///
+ /// The content type of the request body when it couldn't be inferred from the description.
+ ///
+ RequestBodyContentType,
}
public class CodeParameter : CodeTerminalWithKind, ICloneable, IDocumentedElement, IDeprecableElement
diff --git a/src/Kiota.Builder/CodeRenderers/CodeRenderer.cs b/src/Kiota.Builder/CodeRenderers/CodeRenderer.cs
index 29e5f826c9..c8a3bc3272 100644
--- a/src/Kiota.Builder/CodeRenderers/CodeRenderer.cs
+++ b/src/Kiota.Builder/CodeRenderers/CodeRenderer.cs
@@ -3,9 +3,9 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Configuration;
+using Kiota.Builder.OrderComparers;
using Kiota.Builder.Writers;
namespace Kiota.Builder.CodeRenderers;
diff --git a/src/Kiota.Builder/CodeRenderers/PythonCodeRenderer.cs b/src/Kiota.Builder/CodeRenderers/PythonCodeRenderer.cs
index 4898655ebc..3322532b61 100644
--- a/src/Kiota.Builder/CodeRenderers/PythonCodeRenderer.cs
+++ b/src/Kiota.Builder/CodeRenderers/PythonCodeRenderer.cs
@@ -1,4 +1,5 @@
using Kiota.Builder.Configuration;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.CodeRenderers;
public class PythonCodeRenderer : CodeRenderer
diff --git a/src/Kiota.Builder/Configuration/GenerationConfiguration.cs b/src/Kiota.Builder/Configuration/GenerationConfiguration.cs
index c8149068f1..1254f4d2c7 100644
--- a/src/Kiota.Builder/Configuration/GenerationConfiguration.cs
+++ b/src/Kiota.Builder/Configuration/GenerationConfiguration.cs
@@ -105,14 +105,14 @@ public bool CleanOutput
{
get; set;
}
- public HashSet StructuredMimeTypes
+ public StructuredMimeTypesCollection StructuredMimeTypes
{
get; set;
- } = new(4, StringComparer.OrdinalIgnoreCase) {
- "application/json",
- "text/plain",
- "application/x-www-form-urlencoded",
- "multipart/form-data",
+ } = new StructuredMimeTypesCollection {
+ "application/json;q=1",
+ "text/plain;q=0.9",
+ "application/x-www-form-urlencoded;q=0.2",
+ "multipart/form-data;q=0.1",
};
public HashSet IncludePatterns { get; set; } = new(0, StringComparer.OrdinalIgnoreCase);
public HashSet ExcludePatterns { get; set; } = new(0, StringComparer.OrdinalIgnoreCase);
@@ -139,7 +139,7 @@ public object Clone()
Serializers = new(Serializers ?? Enumerable.Empty(), StringComparer.OrdinalIgnoreCase),
Deserializers = new(Deserializers ?? Enumerable.Empty(), StringComparer.OrdinalIgnoreCase),
CleanOutput = CleanOutput,
- StructuredMimeTypes = new(StructuredMimeTypes ?? Enumerable.Empty(), StringComparer.OrdinalIgnoreCase),
+ StructuredMimeTypes = new(StructuredMimeTypes ?? Enumerable.Empty()),
IncludePatterns = new(IncludePatterns ?? Enumerable.Empty(), StringComparer.OrdinalIgnoreCase),
ExcludePatterns = new(ExcludePatterns ?? Enumerable.Empty(), StringComparer.OrdinalIgnoreCase),
ClearCache = ClearCache,
@@ -164,7 +164,7 @@ internal void UpdateConfigurationFromLanguagesInformation(LanguagesInformation l
if (languageInfo.StructuredMimeTypes.Any() &&
comparer.Equals(StructuredMimeTypes, defaultConfiguration.StructuredMimeTypes) &&
!comparer.Equals(languageInfo.StructuredMimeTypes, StructuredMimeTypes))
- StructuredMimeTypes = new(languageInfo.StructuredMimeTypes, StringComparer.OrdinalIgnoreCase);
+ StructuredMimeTypes = new(languageInfo.StructuredMimeTypes);
}
}
#pragma warning restore CA1056
diff --git a/src/Kiota.Builder/Configuration/StructuredMimeTypesCollection.cs b/src/Kiota.Builder/Configuration/StructuredMimeTypesCollection.cs
new file mode 100644
index 0000000000..5b43c39a11
--- /dev/null
+++ b/src/Kiota.Builder/Configuration/StructuredMimeTypesCollection.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace Kiota.Builder.Configuration;
+
+public partial class StructuredMimeTypesCollection : ICollection
+{
+ [GeneratedRegex(@"(?[^;]+);?q?=?(?[\d.]+)?", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline, 2000)]
+ private static partial Regex mimeTypesRegex();
+ private readonly static Regex mimeTypesRegexInstance = mimeTypesRegex();
+ private readonly Dictionary _mimeTypes;
+
+ public int Count => _mimeTypes.Count;
+
+ public bool IsReadOnly => false;
+ public StructuredMimeTypesCollection() : this(Array.Empty()) { }
+ public StructuredMimeTypesCollection(IEnumerable mimeTypes)
+ {
+ ArgumentNullException.ThrowIfNull(mimeTypes);
+ _mimeTypes = mimeTypes.Select(GetKeyAndPriority)
+ .OfType>()
+ .ToDictionary(static x => x.Key, static x => x.Value, StringComparer.OrdinalIgnoreCase);
+ }
+ private static KeyValuePair? GetKeyAndPriority(string rawFormat)
+ {
+ if (string.IsNullOrEmpty(rawFormat))
+ return null;
+ var match = mimeTypesRegexInstance.Match(rawFormat);
+ if (match.Success)
+ {
+ var priority = match.Groups["priority"].Success && float.TryParse(match.Groups["priority"].Value, CultureInfo.InvariantCulture, out var resultPriority) ? resultPriority : 1;
+ return new KeyValuePair(match.Groups["mime"].Value, priority);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ public IEnumerator GetEnumerator()
+ {
+ return _mimeTypes.OrderByDescending(static x => x.Value).Select(NormalizeMimeType).GetEnumerator();
+ }
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ public bool Contains(string item)
+ {
+ if (string.IsNullOrEmpty(item))
+ return false;
+ return _mimeTypes.ContainsKey(item);
+ }
+ public float? GetPriority(string mimeType)
+ {
+ if (string.IsNullOrEmpty(mimeType))
+ return null;
+ return _mimeTypes.TryGetValue(mimeType, out var priority) ? priority : null;
+ }
+
+ public void Add(string item)
+ {
+ if (GetKeyAndPriority(item) is { } result)
+ _mimeTypes.TryAdd(result.Key, result.Value);
+ }
+
+ public void Clear()
+ {
+ _mimeTypes.Clear();
+ }
+
+ ///
+ public void CopyTo(string[] array, int arrayIndex)
+ {
+ _mimeTypes.OrderByDescending(static x => x.Value).Select(NormalizeMimeType).ToArray().CopyTo(array, arrayIndex);
+ }
+ private static string NormalizeMimeType(KeyValuePair mimeType)
+ {
+ return NormalizeMimeType(mimeType.Key, mimeType.Value);
+ }
+ private static string NormalizeMimeType(string key, float value)
+ {
+ return $"{key};q={value}";
+ }
+ ///
+ public bool Remove(string item)
+ {
+ if (GetKeyAndPriority(item) is { } result && _mimeTypes.ContainsKey(result.Key))
+ {
+ _mimeTypes.Remove(result.Key);
+ return true;
+ }
+ else
+ return false;
+ }
+ public IEnumerable GetAcceptedTypes(IEnumerable searchTypes)
+ {
+ ArgumentNullException.ThrowIfNull(searchTypes);
+ return searchTypes.Select(GetKeyAndPriority)
+ .OfType>()
+ .Select(static x => x.Key)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(x => _mimeTypes.TryGetValue(x, out var result) ? NormalizeMimeType(x, result) : null)
+ .OfType()
+ .Order(StringComparer.OrdinalIgnoreCase);
+ }
+ public IEnumerable GetContentTypes(IEnumerable searchTypes)
+ {
+ ArgumentNullException.ThrowIfNull(searchTypes);
+ return searchTypes.Select(GetKeyAndPriority)
+ .OfType>()
+ .Select(static x => x.Key)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(x => _mimeTypes.TryGetValue(x, out var result) ? new KeyValuePair?(new(x, result)) : null)
+ .OfType>()
+ .OrderByDescending(static x => x.Value)
+ .ThenByDescending(static x => x.Key, StringComparer.OrdinalIgnoreCase)
+ .Select(static x => x.Key);
+ }
+}
diff --git a/src/Kiota.Builder/GlobComparer.cs b/src/Kiota.Builder/EqualityComparers/GlobComparer.cs
similarity index 91%
rename from src/Kiota.Builder/GlobComparer.cs
rename to src/Kiota.Builder/EqualityComparers/GlobComparer.cs
index d0c1d11bb5..61a9350137 100644
--- a/src/Kiota.Builder/GlobComparer.cs
+++ b/src/Kiota.Builder/EqualityComparers/GlobComparer.cs
@@ -3,7 +3,7 @@
using System.Diagnostics.CodeAnalysis;
using DotNet.Globbing;
-namespace Kiota.Builder;
+namespace Kiota.Builder.EqualityComparers;
internal class GlobComparer : IEqualityComparer
{
diff --git a/src/Kiota.Builder/EqualityComparers/OpenApiSchemaReferenceComparer.cs b/src/Kiota.Builder/EqualityComparers/OpenApiSchemaReferenceComparer.cs
new file mode 100644
index 0000000000..a0d504b7a0
--- /dev/null
+++ b/src/Kiota.Builder/EqualityComparers/OpenApiSchemaReferenceComparer.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.OpenApi.Models;
+
+namespace Kiota.Builder.EqualityComparers;
+
+internal class OpenApiSchemaReferenceComparer : IEqualityComparer
+{
+ public bool Equals(OpenApiSchema? x, OpenApiSchema? y)
+ {
+ return (x, y) switch
+ {
+ (null, null) => true,
+ (null, _) => false,
+ (_, null) => false,
+ _ when x.Reference is not null && !string.IsNullOrEmpty(x.Reference.Id) && y.Reference is not null && !string.IsNullOrEmpty(y.Reference.Id) =>
+ x.Reference.Id.Equals(y.Reference.Id, StringComparison.OrdinalIgnoreCase),
+ _ => x == y,
+ };
+ }
+ public int GetHashCode([DisallowNull] OpenApiSchema obj)
+ {
+ return obj.Reference is not null && !string.IsNullOrEmpty(obj.Reference.Id) ? obj.Reference.Id.GetHashCode(StringComparison.OrdinalIgnoreCase) : obj.GetHashCode();
+ }
+}
diff --git a/src/Kiota.Builder/OpenApiServerComparer.cs b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs
similarity index 95%
rename from src/Kiota.Builder/OpenApiServerComparer.cs
rename to src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs
index 3bd5cdfe48..da206ac7c5 100644
--- a/src/Kiota.Builder/OpenApiServerComparer.cs
+++ b/src/Kiota.Builder/EqualityComparers/OpenApiServerComparer.cs
@@ -4,7 +4,7 @@
using System.Text.RegularExpressions;
using Microsoft.OpenApi.Models;
-namespace Kiota.Builder;
+namespace Kiota.Builder.EqualityComparers;
internal sealed partial class OpenApiServerComparer : IEqualityComparer
{
diff --git a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs
index 20c5106b98..1a67303f37 100644
--- a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs
+++ b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
-
+using Kiota.Builder.Configuration;
using Microsoft.OpenApi.Models;
namespace Kiota.Builder.Extensions;
@@ -13,33 +13,33 @@ public static class OpenApiOperationExtensions
/// cleans application/vnd.github.mercy-preview+json to application/json
///
private static readonly Regex vendorSpecificCleanup = new(@"[^/]+\+", RegexOptions.Compiled, Constants.DefaultRegexTimeout);
- public static OpenApiSchema? GetResponseSchema(this OpenApiOperation operation, HashSet structuredMimeTypes)
+ internal static OpenApiSchema? GetResponseSchema(this OpenApiOperation operation, StructuredMimeTypesCollection structuredMimeTypes)
{
ArgumentNullException.ThrowIfNull(operation);
// Return Schema that represents all the possible success responses!
return operation.GetResponseSchemas(SuccessCodes, structuredMimeTypes)
.FirstOrDefault();
}
- internal static IEnumerable GetResponseSchemas(this OpenApiOperation operation, HashSet successCodesToUse, HashSet structuredMimeTypes)
+ internal static IEnumerable GetResponseSchemas(this OpenApiOperation operation, HashSet successCodesToUse, StructuredMimeTypesCollection structuredMimeTypes)
{
// Return Schema that represents all the possible success responses!
return operation.Responses.Where(r => successCodesToUse.Contains(r.Key))
.OrderBy(static x => x.Key, StringComparer.OrdinalIgnoreCase)
.SelectMany(re => re.Value.Content.GetValidSchemas(structuredMimeTypes));
}
- public static OpenApiSchema? GetRequestSchema(this OpenApiOperation operation, HashSet structuredMimeTypes)
+ internal static OpenApiSchema? GetRequestSchema(this OpenApiOperation operation, StructuredMimeTypesCollection structuredMimeTypes)
{
ArgumentNullException.ThrowIfNull(operation);
return operation.RequestBody?.Content
.GetValidSchemas(structuredMimeTypes).FirstOrDefault();
}
- private static readonly HashSet multipartMimeTypes = new(1, StringComparer.OrdinalIgnoreCase) { "multipart/form-data" };
- public static bool IsMultipartFormDataSchema(this IDictionary source, HashSet structuredMimeTypes)
+ private static readonly StructuredMimeTypesCollection multipartMimeTypes = new(new string[] { "multipart/form-data" });
+ internal static bool IsMultipartFormDataSchema(this IDictionary source, StructuredMimeTypesCollection structuredMimeTypes)
{
return source.GetValidSchemas(structuredMimeTypes).FirstOrDefault() is OpenApiSchema schema &&
source.GetValidSchemas(multipartMimeTypes).FirstOrDefault() == schema;
}
- public static IEnumerable GetValidSchemas(this IDictionary source, HashSet structuredMimeTypes)
+ internal static IEnumerable GetValidSchemas(this IDictionary source, StructuredMimeTypesCollection structuredMimeTypes)
{
if (!(structuredMimeTypes?.Any() ?? false))
throw new ArgumentNullException(nameof(structuredMimeTypes));
@@ -51,7 +51,7 @@ public static IEnumerable GetValidSchemas(this IDictionary s is not null) ??
Enumerable.Empty();
}
- public static OpenApiSchema? GetResponseSchema(this OpenApiResponse response, HashSet structuredMimeTypes)
+ internal static OpenApiSchema? GetResponseSchema(this OpenApiResponse response, StructuredMimeTypesCollection structuredMimeTypes)
{
ArgumentNullException.ThrowIfNull(response);
return response.Content.GetValidSchemas(structuredMimeTypes).FirstOrDefault();
diff --git a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs
index b641b044d2..c3913ef313 100644
--- a/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs
+++ b/src/Kiota.Builder/Extensions/OpenApiUrlTreeNodeExtensions.cs
@@ -83,12 +83,12 @@ public static IEnumerable GetPathParametersForCurrentSegment(t
///
/// Returns the class name for the node with more or less precision depending on the provided arguments
///
- public static string GetClassName(this OpenApiUrlTreeNode currentNode, HashSet structuredMimeTypes, string? suffix = default, string? prefix = default, OpenApiOperation? operation = default, OpenApiResponse? response = default, OpenApiSchema? schema = default, bool requestBody = false)
+ internal static string GetClassName(this OpenApiUrlTreeNode currentNode, StructuredMimeTypesCollection structuredMimeTypes, string? suffix = default, string? prefix = default, OpenApiOperation? operation = default, OpenApiResponse? response = default, OpenApiSchema? schema = default, bool requestBody = false)
{
ArgumentNullException.ThrowIfNull(currentNode);
return currentNode.GetSegmentName(structuredMimeTypes, suffix, prefix, operation, response, schema, requestBody, static x => x.LastOrDefault() ?? string.Empty);
}
- public static string GetNavigationPropertyName(this OpenApiUrlTreeNode currentNode, HashSet structuredMimeTypes, string? suffix = default, string? prefix = default, OpenApiOperation? operation = default, OpenApiResponse? response = default, OpenApiSchema? schema = default, bool requestBody = false)
+ internal static string GetNavigationPropertyName(this OpenApiUrlTreeNode currentNode, StructuredMimeTypesCollection structuredMimeTypes, string? suffix = default, string? prefix = default, OpenApiOperation? operation = default, OpenApiResponse? response = default, OpenApiSchema? schema = default, bool requestBody = false)
{
ArgumentNullException.ThrowIfNull(currentNode);
var result = currentNode.GetSegmentName(structuredMimeTypes, suffix, prefix, operation, response, schema, requestBody, static x => string.Join(string.Empty, x.Select(static (y, idx) => idx == 0 ? y : y.ToFirstCharacterUpperCase())), false);
@@ -97,7 +97,7 @@ public static string GetNavigationPropertyName(this OpenApiUrlTreeNode currentNo
return result;
}
private static readonly HashSet httpVerbs = new(StringComparer.OrdinalIgnoreCase) { "get", "post", "put", "patch", "delete", "head", "options", "trace" };
- private static string GetSegmentName(this OpenApiUrlTreeNode currentNode, HashSet structuredMimeTypes, string? suffix, string? prefix, OpenApiOperation? operation, OpenApiResponse? response, OpenApiSchema? schema, bool requestBody, Func, string> segmentsReducer, bool skipExtension = true)
+ private static string GetSegmentName(this OpenApiUrlTreeNode currentNode, StructuredMimeTypesCollection structuredMimeTypes, string? suffix, string? prefix, OpenApiOperation? operation, OpenApiResponse? response, OpenApiSchema? schema, bool requestBody, Func, string> segmentsReducer, bool skipExtension = true)
{
var referenceName = schema?.Reference?.GetClassName();
var rawClassName = referenceName is not null && !string.IsNullOrEmpty(referenceName) ?
diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj
index 57ba2c0c1d..6efd91d4e2 100644
--- a/src/Kiota.Builder/Kiota.Builder.csproj
+++ b/src/Kiota.Builder/Kiota.Builder.csproj
@@ -53,9 +53,13 @@
-
+
+
+
+
-
+
\ No newline at end of file
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index 0d3b8cb576..07edb94940 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -16,6 +16,7 @@
using Kiota.Builder.CodeDOM;
using Kiota.Builder.CodeRenderers;
using Kiota.Builder.Configuration;
+using Kiota.Builder.EqualityComparers;
using Kiota.Builder.Exceptions;
using Kiota.Builder.Extensions;
using Kiota.Builder.Lock;
@@ -1419,11 +1420,12 @@ private void CreateOperationMethods(OpenApiUrlTreeNode currentNode, OperationTyp
Parent = parentClass,
Deprecation = deprecationInformation,
};
- if (schema != null)
+ var mediaTypes = schema switch
{
- var mediaType = operation.Responses.Values.SelectMany(static x => x.Content).First(x => x.Value.Schema == schema).Key;
- generatorMethod.AcceptedResponseTypes.Add(mediaType);
- }
+ null => operation.Responses.Values.SelectMany(static x => x.Content).Select(static x => x.Key),
+ _ => config.StructuredMimeTypes.GetAcceptedTypes(operation.Responses.Values.SelectMany(static x => x.Content).Where(x => schemaReferenceComparer.Equals(schema, x.Value.Schema)).Select(static x => x.Key)),
+ };
+ generatorMethod.AddAcceptedResponsesTypes(mediaTypes);
if (config.Language == GenerationLanguage.CLI)
SetPathAndQueryParameters(generatorMethod, currentNode, operation);
AddRequestBuilderMethodParameters(currentNode, operationType, operation, requestConfigClass, generatorMethod);
@@ -1435,6 +1437,7 @@ private void CreateOperationMethods(OpenApiUrlTreeNode currentNode, OperationTyp
logger.LogWarning(ex, "Could not create method for {Operation} in {Path} because the schema was invalid", operation.OperationId, currentNode.Path);
}
}
+ private static readonly OpenApiSchemaReferenceComparer schemaReferenceComparer = new();
private static readonly Func GetCodeParameterFromApiParameter = x =>
{
var codeName = x.Name.SanitizeParameterNameForCodeSymbols();
@@ -1526,7 +1529,7 @@ private void AddRequestBuilderMethodParameters(OpenApiUrlTreeNode currentNode, O
var mediaType = operation.RequestBody.Content.First(x => x.Value.Schema == requestBodySchema).Value;
foreach (var encodingEntry in mediaType.Encoding
.Where(x => !string.IsNullOrEmpty(x.Value.ContentType) &&
- config.StructuredMimeTypes.Contains(x.Value.ContentType.Split(';', StringSplitOptions.RemoveEmptyEntries)[0])))
+ config.StructuredMimeTypes.Contains(x.Value.ContentType)))
{
if (CreateModelDeclarations(currentNode, requestBodySchema.Properties[encodingEntry.Key], operation, method, $"{operationType}RequestBody", isRequestBody: true) is CodeType propertyType &&
propertyType.TypeDefinition is not null)
@@ -1550,7 +1553,7 @@ private void AddRequestBuilderMethodParameters(OpenApiUrlTreeNode currentNode, O
},
Deprecation = requestBodySchema.GetDeprecationInformation(),
});
- method.RequestBodyContentType = operation.RequestBody.Content.First(x => x.Value.Schema == requestBodySchema).Key;
+ method.RequestBodyContentType = config.StructuredMimeTypes.GetContentTypes(operation.RequestBody.Content.Where(x => schemaReferenceComparer.Equals(x.Value.Schema, requestBodySchema)).Select(static x => x.Key)).First();
}
else if (operation.RequestBody?.Content?.Any() ?? false)
{
@@ -1571,6 +1574,22 @@ private void AddRequestBuilderMethodParameters(OpenApiUrlTreeNode currentNode, O
},
};
method.AddParameter(nParam);
+ var contentTypes = operation.RequestBody.Content.Select(static x => x.Key).ToArray();
+ if (contentTypes.Length == 1 && !"*/*".Equals(contentTypes[0], StringComparison.OrdinalIgnoreCase))
+ method.RequestBodyContentType = contentTypes[0];
+ else
+ method.AddParameter(new CodeParameter
+ {
+ Kind = CodeParameterKind.RequestBodyContentType,
+ Name = "contentType",
+ Optional = false,
+ Type = new CodeType
+ {
+ Name = "string",
+ IsExternal = true,
+ IsNullable = false,
+ },
+ });
}
method.AddParameter(new CodeParameter
{
diff --git a/src/Kiota.Builder/Lock/KiotaLock.cs b/src/Kiota.Builder/Lock/KiotaLock.cs
index 099d781477..a299234a5d 100644
--- a/src/Kiota.Builder/Lock/KiotaLock.cs
+++ b/src/Kiota.Builder/Lock/KiotaLock.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Kiota.Builder.Configuration;
namespace Kiota.Builder.Lock;
@@ -70,7 +71,9 @@ public bool IncludeAdditionalData
///
/// The structured mime types used for this client.
///
- public HashSet StructuredMimeTypes { get; set; } = new();
+#pragma warning disable CA1002
+ public List StructuredMimeTypes { get; set; } = new();
+#pragma warning restore CA1002
///
/// The path patterns for API endpoints to include for this client.
///
@@ -100,7 +103,7 @@ public void UpdateGenerationConfigurationFromLock(GenerationConfiguration config
config.IncludeAdditionalData = IncludeAdditionalData;
config.Serializers = Serializers;
config.Deserializers = Deserializers;
- config.StructuredMimeTypes = StructuredMimeTypes;
+ config.StructuredMimeTypes = new(StructuredMimeTypes);
config.IncludePatterns = IncludePatterns;
config.ExcludePatterns = ExcludePatterns;
config.OpenAPIFilePath = DescriptionLocation;
@@ -127,7 +130,7 @@ public KiotaLock(GenerationConfiguration config)
IncludeAdditionalData = config.IncludeAdditionalData;
Serializers = config.Serializers;
Deserializers = config.Deserializers;
- StructuredMimeTypes = config.StructuredMimeTypes;
+ StructuredMimeTypes = config.StructuredMimeTypes.ToList();
IncludePatterns = config.IncludePatterns;
ExcludePatterns = config.ExcludePatterns;
DescriptionLocation = config.OpenAPIFilePath;
diff --git a/src/Kiota.Builder/BaseCodeParameterOrderComparer.cs b/src/Kiota.Builder/OrderComparers/BaseCodeParameterOrderComparer.cs
similarity index 77%
rename from src/Kiota.Builder/BaseCodeParameterOrderComparer.cs
rename to src/Kiota.Builder/OrderComparers/BaseCodeParameterOrderComparer.cs
index eab584983c..c350366388 100644
--- a/src/Kiota.Builder/BaseCodeParameterOrderComparer.cs
+++ b/src/Kiota.Builder/OrderComparers/BaseCodeParameterOrderComparer.cs
@@ -1,7 +1,7 @@
using System;
using Kiota.Builder.CodeDOM;
-namespace Kiota.Builder;
+namespace Kiota.Builder.OrderComparers;
public class BaseCodeParameterOrderComparer : BaseStringComparisonComparer
{
public override int Compare(CodeParameter? x, CodeParameter? y)
@@ -28,12 +28,13 @@ protected virtual int GetKindOrderHint(CodeParameterKind kind)
CodeParameterKind.Path => 4,
CodeParameterKind.RequestConfiguration => 5,
CodeParameterKind.RequestBody => 6,
- CodeParameterKind.Serializer => 7,
- CodeParameterKind.BackingStore => 8,
- CodeParameterKind.SetterValue => 9,
- CodeParameterKind.ParseNode => 10,
- CodeParameterKind.Custom => 11,
- _ => 12,
+ CodeParameterKind.RequestBodyContentType => 7,
+ CodeParameterKind.Serializer => 8,
+ CodeParameterKind.BackingStore => 9,
+ CodeParameterKind.SetterValue => 10,
+ CodeParameterKind.ParseNode => 11,
+ CodeParameterKind.Custom => 12,
+ _ => 13,
};
}
private const int OptionalWeight = 10000;
diff --git a/src/Kiota.Builder/CodeElementOrderComparer.cs b/src/Kiota.Builder/OrderComparers/CodeElementOrderComparer.cs
similarity index 97%
rename from src/Kiota.Builder/CodeElementOrderComparer.cs
rename to src/Kiota.Builder/OrderComparers/CodeElementOrderComparer.cs
index c4fe158f41..e209f7e182 100644
--- a/src/Kiota.Builder/CodeElementOrderComparer.cs
+++ b/src/Kiota.Builder/OrderComparers/CodeElementOrderComparer.cs
@@ -1,9 +1,8 @@
using System;
-using System.Collections.Generic;
using System.Linq;
using Kiota.Builder.CodeDOM;
-namespace Kiota.Builder;
+namespace Kiota.Builder.OrderComparers;
public class CodeElementOrderComparer : BaseStringComparisonComparer
{
public override int Compare(CodeElement? x, CodeElement? y)
diff --git a/src/Kiota.Builder/CodeElementOrderComparerPython.cs b/src/Kiota.Builder/OrderComparers/CodeElementOrderComparerPython.cs
similarity index 95%
rename from src/Kiota.Builder/CodeElementOrderComparerPython.cs
rename to src/Kiota.Builder/OrderComparers/CodeElementOrderComparerPython.cs
index a15461e36e..5e39989ce9 100644
--- a/src/Kiota.Builder/CodeElementOrderComparerPython.cs
+++ b/src/Kiota.Builder/OrderComparers/CodeElementOrderComparerPython.cs
@@ -1,6 +1,6 @@
using Kiota.Builder.CodeDOM;
-namespace Kiota.Builder;
+namespace Kiota.Builder.OrderComparers;
public class CodeElementOrderComparerPython : CodeElementOrderComparer
{
protected override int GetTypeFactor(CodeElement element)
diff --git a/src/Kiota.Builder/CodeElementOrderComparerWithExternalMethods.cs b/src/Kiota.Builder/OrderComparers/CodeElementOrderComparerWithExternalMethods.cs
similarity index 94%
rename from src/Kiota.Builder/CodeElementOrderComparerWithExternalMethods.cs
rename to src/Kiota.Builder/OrderComparers/CodeElementOrderComparerWithExternalMethods.cs
index 6f94eafc3b..950c317bba 100644
--- a/src/Kiota.Builder/CodeElementOrderComparerWithExternalMethods.cs
+++ b/src/Kiota.Builder/OrderComparers/CodeElementOrderComparerWithExternalMethods.cs
@@ -1,6 +1,6 @@
using Kiota.Builder.CodeDOM;
-namespace Kiota.Builder;
+namespace Kiota.Builder.OrderComparers;
public class CodeElementOrderComparerWithExternalMethods : CodeElementOrderComparer
{
protected override int GetTypeFactor(CodeElement element)
diff --git a/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs b/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs
index fdeb7577dd..254525fa4f 100644
--- a/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs
+++ b/src/Kiota.Builder/Validation/UrlFormEncodedComplex.cs
@@ -1,7 +1,6 @@
-using System;
-using System.Collections.Generic;
using System.Linq;
+using Kiota.Builder.Configuration;
using Kiota.Builder.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Validations;
@@ -9,7 +8,7 @@
namespace Kiota.Builder.Validation;
public class UrlFormEncodedComplex : ValidationRule
{
- private static readonly HashSet validContentTypes = new(StringComparer.OrdinalIgnoreCase) {
+ private static readonly StructuredMimeTypesCollection validContentTypes = new() {
"application/x-www-form-urlencoded",
};
public UrlFormEncodedComplex() : base(static (context, operation) =>
diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
index 8bbf7c0845..39724792ba 100644
--- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
-
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Extensions;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.Writers.CSharp;
public class CodeMethodWriter : BaseElementWriter
@@ -50,7 +50,8 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w
var returnTypeWithoutCollectionInformation = conventions.GetTypeString(codeElement.ReturnType, codeElement, false);
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var requestConfig = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
- var requestParams = new RequestParams(requestBodyParam, requestConfig);
+ var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType);
+ var requestParams = new RequestParams(requestBodyParam, requestConfig, requestContentType);
switch (codeElement.Kind)
{
case CodeMethodKind.Serializer:
@@ -89,7 +90,7 @@ protected virtual void HandleMethodKind(CodeMethod codeElement, LanguageWriter w
case CodeMethodKind.CommandBuilder:
var origParams = codeElement.OriginalMethod?.Parameters ?? codeElement.Parameters;
requestBodyParam = origParams.OfKind(CodeParameterKind.RequestBody);
- requestParams = new RequestParams(requestBodyParam, null);
+ requestParams = new RequestParams(requestBodyParam, null, null);
WriteCommandBuilderBody(codeElement, parentClass, requestParams, isVoid, returnType, writer);
break;
case CodeMethodKind.Factory:
@@ -375,7 +376,7 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re
.Methods
.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestGenerator) && x.HttpMethod == codeElement.HttpMethod)
?.Name;
- var parametersList = new CodeParameter?[] { requestParams.requestBody, requestParams.requestConfiguration }
+ var parametersList = new CodeParameter?[] { requestParams.requestBody, requestParams.requestContentType, requestParams.requestConfiguration }
.Select(static x => x?.Name).Where(static x => x != null).Aggregate(static (x, y) => $"{x}, {y}");
writer.WriteLine($"var requestInfo = {generatorMethodName}({parametersList});");
var errorMappingVarName = "default";
@@ -433,13 +434,18 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
writer.CloseBlock();
}
- if (codeElement.AcceptedResponseTypes.Any())
- writer.WriteLine($"{RequestInfoVarName}.Headers.TryAdd(\"Accept\", \"{string.Join(", ", codeElement.AcceptedResponseTypes)}\");");
+ if (codeElement.ShouldAddAcceptHeader)
+ writer.WriteLine($"{RequestInfoVarName}.Headers.TryAdd(\"Accept\", \"{codeElement.AcceptHeaderValue}\");");
if (requestParams.requestBody != null)
{
var suffix = requestParams.requestBody.Type.IsCollection ? "Collection" : string.Empty;
if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
- writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name});");
+ {
+ if (requestParams.requestContentType is not null)
+ writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name}, {requestParams.requestContentType.Name});");
+ else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType))
+ writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\");");
+ }
else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty)
if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase)))
writer.WriteLine($"{RequestInfoVarName}.SetContentFromParsable({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});");
diff --git a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs
index 7055214838..58a0062344 100644
--- a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs
@@ -24,7 +24,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
writer.IncreaseIndent();
var requestOptionsParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
- var requestParams = new RequestParams(requestBodyParam, requestOptionsParam);
+ var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType);
+ var requestParams = new RequestParams(requestBodyParam, requestOptionsParam, requestContentType);
switch (codeElement.Kind)
{
case CodeMethodKind.Serializer:
@@ -819,7 +820,6 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
var requestAdapterPropertyName = BaseRequestBuilderVarName + "." + parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter)?.Name.ToFirstCharacterUpperCase();
var contextParameterName = codeElement.Parameters.OfKind(CodeParameterKind.Cancellation)?.Name.ToFirstCharacterLowerCase();
writer.WriteLine($"{RequestInfoVarName} := {conventions.AbstractionsHash}.NewRequestInformation()");
-
if (requestParams.requestConfiguration != null)
{
var headers = requestParams.Headers;
@@ -854,14 +854,19 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
writer.WriteLines($"{RequestInfoVarName}.UrlTemplate = {GetPropertyCall(urlTemplateProperty, "\"\"")}",
$"{RequestInfoVarName}.PathParameters = {GetPropertyCall(urlTemplateParamsProperty, "\"\"")}");
writer.WriteLine($"{RequestInfoVarName}.Method = {conventions.AbstractionsHash}.{codeElement.HttpMethod.Value.ToString().ToUpperInvariant()}");
- if (codeElement.AcceptedResponseTypes.Any())
- writer.WriteLine($"{RequestInfoVarName}.Headers.TryAdd(\"Accept\", \"{string.Join(", ", codeElement.AcceptedResponseTypes)}\")");
+ if (codeElement.ShouldAddAcceptHeader)
+ writer.WriteLine($"{RequestInfoVarName}.Headers.TryAdd(\"Accept\", \"{codeElement.AcceptHeaderValue}\")");
if (requestParams.requestBody != null)
{
var bodyParamReference = $"{requestParams.requestBody.Name.ToFirstCharacterLowerCase()}";
var collectionSuffix = requestParams.requestBody.Type.IsCollection ? "Collection" : string.Empty;
- if (requestParams.requestBody.Type.Name.Equals("binary", StringComparison.OrdinalIgnoreCase))
- writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({bodyParamReference})");
+ if (requestParams.requestBody.Type.Name.Equals("binary", StringComparison.OrdinalIgnoreCase) || requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
+ {
+ if (requestParams.requestContentType is not null)
+ writer.WriteLine($"{RequestInfoVarName}.SetStreamContentAndContentType({bodyParamReference}, {requestParams.requestContentType.Name.ToFirstCharacterLowerCase()})");
+ else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType))
+ writer.WriteLine($"{RequestInfoVarName}.SetStreamContentAndContentType({bodyParamReference}, \"{codeElement.RequestBodyContentType}\")");
+ }
else if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.TypeDefinition is CodeInterface || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase)))
{
if (bodyType.IsCollection)
diff --git a/src/Kiota.Builder/Writers/Go/GoCodeParameterOrderComparer.cs b/src/Kiota.Builder/Writers/Go/GoCodeParameterOrderComparer.cs
index 1e5ed5a0bf..934d2c2fe3 100644
--- a/src/Kiota.Builder/Writers/Go/GoCodeParameterOrderComparer.cs
+++ b/src/Kiota.Builder/Writers/Go/GoCodeParameterOrderComparer.cs
@@ -1,4 +1,5 @@
using Kiota.Builder.CodeDOM;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.Writers.Go;
@@ -16,11 +17,12 @@ protected override int GetKindOrderHint(CodeParameterKind kind)
CodeParameterKind.Path => 4,
CodeParameterKind.RequestConfiguration => 5,
CodeParameterKind.RequestBody => 6,
- CodeParameterKind.Serializer => 7,
- CodeParameterKind.BackingStore => 8,
- CodeParameterKind.SetterValue => 9,
- CodeParameterKind.ParseNode => 10,
- CodeParameterKind.Custom => 11,
+ CodeParameterKind.RequestBodyContentType => 7,
+ CodeParameterKind.Serializer => 8,
+ CodeParameterKind.BackingStore => 9,
+ CodeParameterKind.SetterValue => 10,
+ CodeParameterKind.ParseNode => 11,
+ CodeParameterKind.Custom => 12,
_ => 13,
};
}
diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
index 70f05ece23..32c2834154 100644
--- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
@@ -4,6 +4,7 @@
using System.Text.RegularExpressions;
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Extensions;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.Writers.Java;
public class CodeMethodWriter : BaseElementWriter
@@ -24,7 +25,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
var inherits = parentClass.StartBlock.Inherits != null && !parentClass.IsErrorDefinition;
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var configParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
- var requestParams = new RequestParams(requestBodyParam, configParam);
+ var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType);
+ var requestParams = new RequestParams(requestBodyParam, configParam, requestContentType);
AddNullChecks(codeElement, writer);
switch (codeElement.Kind)
{
@@ -566,8 +568,8 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
currentClass.GetPropertyOfKind(CodePropertyKind.UrlTemplate) is CodeProperty urlTemplateProperty)
writer.WriteLines($"{RequestInfoVarName}.urlTemplate = {GetPropertyCall(urlTemplateProperty, "\"\"")};",
$"{RequestInfoVarName}.pathParameters = {GetPropertyCall(urlTemplateParamsProperty, "null")};");
- if (codeElement.AcceptedResponseTypes.Any())
- writer.WriteLine($"{RequestInfoVarName}.headers.tryAdd(\"Accept\", \"{string.Join(", ", codeElement.AcceptedResponseTypes)}\");");
+ if (codeElement.ShouldAddAcceptHeader)
+ writer.WriteLine($"{RequestInfoVarName}.headers.tryAdd(\"Accept\", \"{codeElement.AcceptHeaderValue}\");");
if (requestParams.requestBody != null &&
currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty)
@@ -575,7 +577,12 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
var toArrayPostfix = requestParams.requestBody.Type.IsCollection ? $".toArray(new {requestParams.requestBody.Type.Name}[0])" : string.Empty;
var collectionPostfix = requestParams.requestBody.Type.IsCollection ? "Collection" : string.Empty;
if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
- writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name});");
+ {
+ if (requestParams.requestContentType is not null)
+ writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, {requestParams.requestContentType.Name});");
+ else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType))
+ writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\");");
+ }
else if (requestParams.requestBody.Type is CodeType bodyType && (bodyType.TypeDefinition is CodeClass || bodyType.Name.Equals("MultipartBody", StringComparison.OrdinalIgnoreCase)))
writer.WriteLine($"{RequestInfoVarName}.setContentFromParsable({requestAdapterProperty.Name}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name}{toArrayPostfix});");
else
diff --git a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
index 01fa5de23b..b439ea8e0a 100644
--- a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
@@ -3,6 +3,7 @@
using System.Linq;
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Extensions;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.Writers.Php;
public class CodeMethodWriter : BaseElementWriter
{
@@ -29,7 +30,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
codeClass.IsOfKind(CodeClassKind.Model);
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var config = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
- var requestParams = new RequestParams(requestBodyParam, config);
+ var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType);
+ var requestParams = new RequestParams(requestBodyParam, config, requestContentType);
WriteMethodPhpDocs(codeElement, writer);
WriteMethodsAndParameters(codeElement, writer, codeElement.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor));
@@ -561,7 +563,12 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
{
var suffix = requestParams.requestBody.Type.IsCollection ? "Collection" : string.Empty;
if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
- writer.WriteLine($"{RequestInfoVarName}->setStreamContent({conventions.GetParameterName(requestParams.requestBody)});");
+ {
+ if (requestParams.requestContentType is not null)
+ writer.WriteLine($"{RequestInfoVarName}->setStreamContent({conventions.GetParameterName(requestParams.requestBody)}, {conventions.GetParameterName(requestParams.requestContentType)});");
+ else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType))
+ writer.WriteLine($"{RequestInfoVarName}->setStreamContent({conventions.GetParameterName(requestParams.requestBody)}, \"{codeElement.RequestBodyContentType}\");");
+ }
else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty)
if (requestParams.requestBody.Type is CodeType bodyType && bodyType.TypeDefinition is CodeClass)
writer.WriteLine($"{RequestInfoVarName}->setContentFromParsable{suffix}($this->{requestAdapterProperty.Name.ToFirstCharacterLowerCase()}, \"{codeElement.RequestBodyContentType}\", {conventions.GetParameterName(requestParams.requestBody)});");
@@ -598,8 +605,8 @@ private void WriteRequestConfiguration(RequestParams requestParams, LanguageWrit
private void WriteAcceptHeaderDef(CodeMethod codeMethod, LanguageWriter writer)
{
- if (codeMethod.AcceptedResponseTypes.Any())
- writer.WriteLine($"{RequestInfoVarName}->tryAddHeader('Accept', \"{string.Join(", ", codeMethod.AcceptedResponseTypes)}\");");
+ if (codeMethod.ShouldAddAcceptHeader)
+ writer.WriteLine($"{RequestInfoVarName}->tryAddHeader('Accept', \"{codeMethod.AcceptHeaderValue}\");");
}
private void WriteDeserializerBody(CodeClass parentClass, LanguageWriter writer, CodeMethod method, bool extendsModelClass = false)
{
diff --git a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs
index 9a400cd7df..48dd0bfb27 100644
--- a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs
@@ -36,7 +36,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
var inherits = parentClass.StartBlock.Inherits != null && !parentClass.IsErrorDefinition;
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var requestConfigParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
- var requestParams = new RequestParams(requestBodyParam, requestConfigParam);
+ var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType);
+ var requestParams = new RequestParams(requestBodyParam, requestConfigParam, requestContentType);
if (!codeElement.IsOfKind(CodeMethodKind.Setter) &&
!(codeElement.IsOfKind(CodeMethodKind.Constructor) && parentClass.IsOfKind(CodeClassKind.RequestBuilder)))
foreach (var parameter in codeElement.Parameters.Where(static x => !x.Optional).OrderBy(static x => x.Name))
@@ -616,8 +617,8 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
writer.WriteLines($"{RequestInfoVarName}.url_template = {GetPropertyCall(urlTemplateProperty, "''")}",
$"{RequestInfoVarName}.path_parameters = {GetPropertyCall(urlTemplateParamsProperty, "''")}");
writer.WriteLine($"{RequestInfoVarName}.http_method = Method.{codeElement.HttpMethod.Value.ToString().ToUpperInvariant()}");
- if (codeElement.AcceptedResponseTypes.Any())
- writer.WriteLine($"{RequestInfoVarName}.try_add_request_header(\"Accept\", \"{string.Join(", ", codeElement.AcceptedResponseTypes)}\")");
+ if (codeElement.ShouldAddAcceptHeader)
+ writer.WriteLine($"{RequestInfoVarName}.try_add_request_header(\"Accept\", \"{codeElement.AcceptHeaderValue}\")");
if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty)
UpdateRequestInformationFromRequestBody(codeElement, requestParams, requestAdapterProperty, writer);
writer.WriteLine($"return {RequestInfoVarName}");
@@ -838,7 +839,12 @@ private void UpdateRequestInformationFromRequestBody(CodeMethod codeElement, Req
if (requestParams.requestBody != null)
{
if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
- writer.WriteLine($"{RequestInfoVarName}.set_stream_content({requestParams.requestBody.Name})");
+ {
+ if (requestParams.requestContentType is not null)
+ writer.WriteLine($"{RequestInfoVarName}.set_stream_content({requestParams.requestBody.Name}, {requestParams.requestContentType.Name})");
+ else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType))
+ writer.WriteLine($"{RequestInfoVarName}.set_stream_content({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\")");
+ }
else
{
var setMethodName = requestParams.requestBody.Type is CodeType bodyType && bodyType.TypeDefinition is CodeClass ? "set_content_from_parsable" : "set_content_from_scalar";
diff --git a/src/Kiota.Builder/Writers/Python/PythonCodeParameterOrderComparer.cs b/src/Kiota.Builder/Writers/Python/PythonCodeParameterOrderComparer.cs
index c6ff579191..1cd8dc6795 100644
--- a/src/Kiota.Builder/Writers/Python/PythonCodeParameterOrderComparer.cs
+++ b/src/Kiota.Builder/Writers/Python/PythonCodeParameterOrderComparer.cs
@@ -1,4 +1,5 @@
using Kiota.Builder.CodeDOM;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.Writers.Python;
public class PythonCodeParameterOrderComparer : BaseCodeParameterOrderComparer
@@ -14,11 +15,12 @@ protected override int GetKindOrderHint(CodeParameterKind kind)
CodeParameterKind.Path => 4,
CodeParameterKind.RequestConfiguration => 5,
CodeParameterKind.RequestBody => 6,
- CodeParameterKind.Serializer => 7,
- CodeParameterKind.BackingStore => 8,
- CodeParameterKind.SetterValue => 9,
- CodeParameterKind.ParseNode => 10,
- CodeParameterKind.Custom => 11,
+ CodeParameterKind.RequestBodyContentType => 7,
+ CodeParameterKind.Serializer => 8,
+ CodeParameterKind.BackingStore => 9,
+ CodeParameterKind.SetterValue => 10,
+ CodeParameterKind.ParseNode => 11,
+ CodeParameterKind.Custom => 12,
_ => 13,
};
}
diff --git a/src/Kiota.Builder/Writers/RequestParams.cs b/src/Kiota.Builder/Writers/RequestParams.cs
index db8b1cc3f3..a62fbe627d 100644
--- a/src/Kiota.Builder/Writers/RequestParams.cs
+++ b/src/Kiota.Builder/Writers/RequestParams.cs
@@ -1,7 +1,7 @@
using Kiota.Builder.CodeDOM;
namespace Kiota.Builder.Writers;
-public record RequestParams(CodeParameter? requestBody, CodeParameter? requestConfiguration)
+public record RequestParams(CodeParameter? requestBody, CodeParameter? requestConfiguration, CodeParameter? requestContentType)
{
public CodeProperty? Headers => requestConfiguration?.GetHeadersProperty();
public CodeProperty? QueryParameters => requestConfiguration?.GetQueryProperty();
diff --git a/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs
index cbccdf170a..950301d162 100644
--- a/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/Ruby/CodeMethodWriter.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
-
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Extensions;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.Writers.Ruby;
public class CodeMethodWriter : BaseElementWriter
@@ -21,7 +21,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
var inherits = parentClass.StartBlock.Inherits != null;
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var config = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
- var requestParams = new RequestParams(requestBodyParam, config);
+ var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType);
+ var requestParams = new RequestParams(requestBodyParam, config, requestContentType);
WriteMethodPrototype(codeElement, writer);
AddNullChecks(codeElement, writer);
switch (codeElement.Kind)
@@ -301,7 +302,12 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
if (requestParams.requestBody != null)
{
if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
- writer.WriteLine($"request_info.set_stream_content({requestParams.requestBody.Name})");
+ {
+ if (requestParams.requestContentType is not null)
+ writer.WriteLine($"request_info.set_stream_content({requestParams.requestBody.Name}, {requestParams.requestContentType.Name})");
+ else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType))
+ writer.WriteLine($"request_info.set_stream_content({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\")");
+ }
else if (parentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty)
writer.WriteLine($"request_info.set_content_from_parsable(@{requestAdapterProperty.Name.ToSnakeCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name})");
}
@@ -311,8 +317,8 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
writer.WriteLines($"request_info.url_template = {GetPropertyCall(urlTemplateProperty, "''")}",
$"request_info.path_parameters = {GetPropertyCall(urlTemplateParamsProperty, "''")}");
writer.WriteLine($"request_info.http_method = :{codeElement.HttpMethod.Value.ToString().ToUpperInvariant()}");
- if (codeElement.AcceptedResponseTypes.Any())
- writer.WriteLine($"request_info.headers.try_add('Accept', '{string.Join(", ", codeElement.AcceptedResponseTypes)}')");
+ if (codeElement.ShouldAddAcceptHeader)
+ writer.WriteLine($"request_info.headers.try_add('Accept', '{codeElement.AcceptHeaderValue}')");
writer.WriteLine("return request_info");
}
private static string GetPropertyCall(CodeProperty property, string defaultValue) => property == null ? defaultValue : $"@{property.NamePrefix}{property.Name.ToSnakeCase()}";
diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs
index 42f5354569..5885e248e1 100644
--- a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
-
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Extensions;
+using Kiota.Builder.OrderComparers;
namespace Kiota.Builder.Writers.TypeScript;
public class CodeMethodWriter : BaseElementWriter
@@ -30,7 +30,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
var inherits = parentClass.StartBlock.Inherits != null && !parentClass.IsErrorDefinition;
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var requestConfigParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
- var requestParams = new RequestParams(requestBodyParam, requestConfigParam);
+ var requestContentType = codeElement.Parameters.OfKind(CodeParameterKind.RequestBodyContentType);
+ var requestParams = new RequestParams(requestBodyParam, requestConfigParam, requestContentType);
WriteDefensiveStatements(codeElement, writer);
switch (codeElement.Kind)
{
@@ -365,12 +366,17 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
writer.WriteLines($"{RequestInfoVarName}.urlTemplate = {GetPropertyCall(urlTemplateProperty)};",
$"{RequestInfoVarName}.pathParameters = {GetPropertyCall(urlTemplateParamsProperty)};");
writer.WriteLine($"{RequestInfoVarName}.httpMethod = HttpMethod.{codeElement.HttpMethod.Value.ToString().ToUpperInvariant()};");
- if (codeElement.AcceptedResponseTypes.Any())
- writer.WriteLine($"{RequestInfoVarName}.tryAddRequestHeaders(\"Accept\", \"{string.Join(", ", codeElement.AcceptedResponseTypes)}\");");
+ if (codeElement.ShouldAddAcceptHeader)
+ writer.WriteLine($"{RequestInfoVarName}.tryAddRequestHeaders(\"Accept\", \"{codeElement.AcceptHeaderValue}\");");
if (requestParams.requestBody != null)
{
if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
- writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name});");
+ {
+ if (requestParams.requestContentType is not null)
+ writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, {requestParams.requestContentType.Name.ToFirstCharacterLowerCase()});");
+ else if (!string.IsNullOrEmpty(codeElement.RequestBodyContentType))
+ writer.WriteLine($"{RequestInfoVarName}.setStreamContent({requestParams.requestBody.Name}, \"{codeElement.RequestBodyContentType}\");");
+ }
else if (currentClass.GetPropertyOfKind(CodePropertyKind.RequestAdapter) is CodeProperty requestAdapterProperty)
{
ComposeContentInRequestGeneratorBody(requestParams.requestBody, requestAdapterProperty, codeElement.RequestBodyContentType, writer);
diff --git a/src/kiota/Handlers/KiotaGenerationCommandHandler.cs b/src/kiota/Handlers/KiotaGenerationCommandHandler.cs
index c94e794751..bb95aec6d4 100644
--- a/src/kiota/Handlers/KiotaGenerationCommandHandler.cs
+++ b/src/kiota/Handlers/KiotaGenerationCommandHandler.cs
@@ -107,9 +107,8 @@ public override async Task InvokeAsync(InvocationContext context)
.SelectMany(static x => x.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
.ToHashSet(StringComparer.OrdinalIgnoreCase);
if (structuredMimeTypes.Any())
- Configuration.Generation.StructuredMimeTypes = structuredMimeTypes.SelectMany(static x => x.Split(new[] { ' ' }))
- .Select(static x => x.TrimQuotes())
- .ToHashSet(StringComparer.OrdinalIgnoreCase);
+ Configuration.Generation.StructuredMimeTypes = new(structuredMimeTypes.SelectMany(static x => x.Split(new[] { ' ' }))
+ .Select(static x => x.TrimQuotes()));
Configuration.Generation.OpenAPIFilePath = GetAbsolutePath(Configuration.Generation.OpenAPIFilePath);
Configuration.Generation.OutputPath = NormalizeSlashesInPath(GetAbsolutePath(Configuration.Generation.OutputPath));
diff --git a/src/kiota/KiotaConfigurationExtensions.cs b/src/kiota/KiotaConfigurationExtensions.cs
index 09fccae1a6..a44dce586b 100644
--- a/src/kiota/KiotaConfigurationExtensions.cs
+++ b/src/kiota/KiotaConfigurationExtensions.cs
@@ -60,14 +60,27 @@ public static void BindConfiguration(this KiotaConfiguration configObject, IConf
configObject.Generation.IncludeAdditionalData = bool.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.IncludeAdditionalData)}"], out var includeAdditionalData) && includeAdditionalData;
configObject.Generation.CleanOutput = bool.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.CleanOutput)}"], out var cleanOutput) && cleanOutput;
configObject.Generation.ClearCache = bool.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.ClearCache)}"], out var clearCache) && clearCache;
+ configObject.Generation.ExcludeBackwardCompatible = bool.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.ExcludeBackwardCompatible)}"], out var excludeBackwardCompatible) && excludeBackwardCompatible;
configObject.Generation.MaxDegreeOfParallelism = int.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.MaxDegreeOfParallelism)}"], out var maxDegreeOfParallelism) ? maxDegreeOfParallelism : configObject.Generation.MaxDegreeOfParallelism;
- configuration.GetSection($"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.StructuredMimeTypes)}").LoadHashSet(configObject.Generation.StructuredMimeTypes);
+ configuration.GetSection($"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.StructuredMimeTypes)}").LoadCollection(configObject.Generation.StructuredMimeTypes);
configuration.GetSection($"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.Serializers)}").LoadHashSet(configObject.Generation.Serializers);
configuration.GetSection($"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.Deserializers)}").LoadHashSet(configObject.Generation.Deserializers);
configuration.GetSection($"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.IncludePatterns)}").LoadHashSet(configObject.Generation.IncludePatterns);
configuration.GetSection($"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.ExcludePatterns)}").LoadHashSet(configObject.Generation.ExcludePatterns);
configuration.GetSection($"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.DisabledValidationRules)}").LoadHashSet(configObject.Generation.DisabledValidationRules);
}
+ private static void LoadCollection(this IConfigurationSection section, ICollection collection)
+ {
+ ArgumentNullException.ThrowIfNull(collection);
+ if (section is null) return;
+ var children = section.GetChildren();
+ if (children.Any() && collection.Any()) collection.Clear();
+ foreach (var item in children)
+ {
+ if (section[item.Key] is string value && !string.IsNullOrEmpty(value))
+ collection.Add(value);
+ }
+ }
private static void LoadHashSet(this IConfigurationSection section, HashSet hashSet)
{
ArgumentNullException.ThrowIfNull(hashSet);
diff --git a/src/kiota/KiotaHost.cs b/src/kiota/KiotaHost.cs
index 66e2e4f37d..79d23c8d0a 100644
--- a/src/kiota/KiotaHost.cs
+++ b/src/kiota/KiotaHost.cs
@@ -367,7 +367,7 @@ private static Command GetGenerateCommand()
var structuredMimeTypesOption = new Option>(
"--structured-mime-types",
() => defaultConfiguration.StructuredMimeTypes.ToList(),
- "The MIME types to use for structured data model generation. Accepts multiple values.");
+ "The MIME types with optional priorities as defined in RFC9110 Accept header to use for structured data model generation. Accepts multiple values.");
structuredMimeTypesOption.AddAlias("-m");
var (includePatterns, excludePatterns) = GetIncludeAndExcludeOptions(defaultConfiguration.IncludePatterns, defaultConfiguration.ExcludePatterns);
diff --git a/tests/Kiota.Builder.Tests/Configuration/StructuredMimeTypesCollectionTests.cs b/tests/Kiota.Builder.Tests/Configuration/StructuredMimeTypesCollectionTests.cs
new file mode 100644
index 0000000000..bd4b21e7d3
--- /dev/null
+++ b/tests/Kiota.Builder.Tests/Configuration/StructuredMimeTypesCollectionTests.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Linq;
+using Kiota.Builder.Configuration;
+using Xunit;
+
+namespace Kiota.Builder.Tests.Configuration;
+
+public sealed class StructuredMimeTypesCollectionTests
+{
+ [Fact]
+ public void Defensive()
+ {
+ Assert.Throws(() => new StructuredMimeTypesCollection(null!));
+ }
+ [Fact]
+ public void ParsesWithOrWithoutPriorities()
+ {
+ var mimeTypes = new StructuredMimeTypesCollection(new[] { "application/json", "application/xml;q=0.8" });
+ Assert.Equal("application/json;q=1", mimeTypes.First(), StringComparer.OrdinalIgnoreCase);
+ Assert.Equal("application/xml;q=0.8", mimeTypes.Last(), StringComparer.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/atom+xml", mimeTypes);
+ Assert.Null(mimeTypes.GetPriority("application/atom+xml"));
+ Assert.Equal(1, mimeTypes.GetPriority("application/json"));
+ Assert.Equal(0.8f, mimeTypes.GetPriority("application/xml"));
+ }
+ [Fact]
+ public void DoesNotAddDuplicates()
+ {
+ Assert.Throws(() => new StructuredMimeTypesCollection(new[] { "application/json", "application/json;q=0.8" }));
+ }
+ [Fact]
+ public void ClearsEntries()
+ {
+ var mimeTypes = new StructuredMimeTypesCollection(new[] { "application/json", "application/xml;q=0.8" });
+ Assert.Equal(2, mimeTypes.Count);
+ mimeTypes.Clear();
+ Assert.Empty(mimeTypes);
+ }
+ [Theory]
+ [InlineData("application/json, application/xml, application/yaml", "application/json", "application/json;q=1")]
+ [InlineData("application/json, application/xml, application/yaml", "application/json,text/plain", "application/json;q=1")]
+ [InlineData("application/json, application/xml, application/yaml;q=0.8", "application/json,text/plain,application/yaml", "application/json;q=1,application/yaml;q=0.8")]
+ public void MatchesAccept(string configuredTypes, string declaredTypes, string expectedTypes)
+ {
+ var mimeTypes = new StructuredMimeTypesCollection(configuredTypes.Split(',').Select(static x => x.Trim()));
+ var result = mimeTypes.GetAcceptedTypes(declaredTypes.Split(',').Select(static x => x.Trim()));
+ var deserializedExpectedTypes = expectedTypes.Split(',').Select(static x => x.Trim());
+ foreach (var expectedType in deserializedExpectedTypes)
+ Assert.Contains(expectedType, result);
+ }
+ [Theory]
+ [InlineData("application/json, application/xml;q=0.9, application/yaml;q=0.8", "application/json", "application/json")]
+ [InlineData("application/json, application/xml;q=0.9, application/yaml;q=0.8", "application/json,text/plain", "application/json")]
+ [InlineData("application/json, application/xml;q=0.9, application/yaml;q=0.8", "application/json,text/plain,application/yaml", "application/json")]
+ public void MatchesContentType(string configuredTypes, string declaredTypes, string expectedTypes)
+ {
+ var mimeTypes = new StructuredMimeTypesCollection(configuredTypes.Split(',').Select(static x => x.Trim()));
+ var result = mimeTypes.GetContentTypes(declaredTypes.Split(',').Select(static x => x.Trim()));
+ var deserializedExpectedTypes = expectedTypes.Split(',').Select(static x => x.Trim());
+ foreach (var expectedType in deserializedExpectedTypes)
+ Assert.Contains(expectedType, result);
+ }
+}
diff --git a/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs b/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs
new file mode 100644
index 0000000000..f77456ac18
--- /dev/null
+++ b/tests/Kiota.Builder.Tests/ContentTypeMappingTests.cs
@@ -0,0 +1,437 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using Kiota.Builder.CodeDOM;
+using Kiota.Builder.Configuration;
+using Kiota.Builder.Extensions;
+using Microsoft.Extensions.Logging;
+using Microsoft.OpenApi.Models;
+using Moq;
+using Xunit;
+
+namespace Kiota.Builder.Tests;
+
+public sealed class ContentTypeMappingTests : IDisposable
+{
+ private readonly List _tempFiles = new();
+ public void Dispose()
+ {
+ foreach (var file in _tempFiles)
+ File.Delete(file);
+ _httpClient.Dispose();
+ GC.SuppressFinalize(this);
+ }
+ private readonly HttpClient _httpClient = new();
+
+ [InlineData("application/json", "206", true, "default", "myobject")]
+ [InlineData("application/json", "206", false, "default", "binary")]
+ [InlineData("application/json", "205", true, "default", "void")]
+ [InlineData("application/json", "205", false, "default", "void")]
+ [InlineData("application/json", "204", true, "default", "void")]
+ [InlineData("application/json", "204", false, "default", "void")]
+ [InlineData("application/json", "203", true, "default", "myobject")]
+ [InlineData("application/json", "203", false, "default", "binary")]
+ [InlineData("application/json", "202", true, "default", "myobject")]
+ [InlineData("application/json", "202", false, "default", "void")]
+ [InlineData("application/json", "201", true, "default", "myobject")]
+ [InlineData("application/json", "201", false, "default", "void")]
+ [InlineData("application/json", "200", true, "default", "myobject")]
+ [InlineData("application/json", "200", false, "default", "binary")]
+ [InlineData("application/json", "2XX", true, "default", "myobject")]
+ [InlineData("application/json", "2XX", false, "default", "binary")]
+ [InlineData("application/xml", "204", true, "default", "void")]
+ [InlineData("application/xml", "204", false, "default", "void")]
+ [InlineData("application/xml", "200", true, "default", "binary")] // MyObject when we support xml deserialization
+ [InlineData("application/xml", "200", false, "default", "binary")]
+ [InlineData("text/xml", "204", true, "default", "void")]
+ [InlineData("text/xml", "204", false, "default", "void")]
+ [InlineData("text/xml", "200", true, "default", "binary")] // MyObject when we support xml deserialization
+ [InlineData("text/xml", "200", false, "default", "binary")]
+ [InlineData("text/yaml", "204", true, "default", "void")]
+ [InlineData("text/yaml", "204", false, "default", "void")]
+ [InlineData("text/yaml", "200", true, "default", "binary")] // MyObject when we support xml deserialization
+ [InlineData("text/yaml", "200", false, "default", "binary")]
+ [InlineData("application/octet-stream", "204", true, "default", "void")]
+ [InlineData("application/octet-stream", "204", false, "default", "void")]
+ [InlineData("application/octet-stream", "200", true, "default", "binary")]
+ [InlineData("application/octet-stream", "200", false, "default", "binary")]
+ [InlineData("text/html", "204", true, "default", "void")]
+ [InlineData("text/html", "204", false, "default", "void")]
+ [InlineData("text/html", "200", true, "default", "binary")]
+ [InlineData("text/html", "200", false, "default", "binary")]
+ [InlineData("*/*", "204", true, "default", "void")]
+ [InlineData("*/*", "204", false, "default", "void")]
+ [InlineData("*/*", "200", true, "default", "binary")]
+ [InlineData("*/*", "200", false, "default", "binary")]
+ [InlineData("text/plain", "204", true, "default", "void")]
+ [InlineData("text/plain", "204", false, "default", "void")]
+ [InlineData("text/plain", "200", true, "default", "myobject")]
+ [InlineData("text/plain", "200", false, "default", "string")]
+ [InlineData("text/plain", "204", true, "application/json", "void")]
+ [InlineData("text/plain", "204", false, "application/json", "void")]
+ [InlineData("text/plain", "200", true, "application/json", "string")]
+ [InlineData("text/plain", "200", false, "application/json", "string")]
+ [InlineData("text/yaml", "204", true, "application/json", "void")]
+ [InlineData("text/yaml", "204", false, "application/json", "void")]
+ [InlineData("text/yaml", "200", true, "application/json", "binary")]
+ [InlineData("text/yaml", "200", false, "application/json", "binary")]
+ [Theory]
+ public void GeneratesTheRightReturnTypeBasedOnContentAndStatus(string contentType, string statusCode, bool addModel, string acceptedContentType, string returnType)
+ {
+ var myObjectSchema = new OpenApiSchema
+ {
+ Type = "object",
+ Properties = new Dictionary {
+ {
+ "id", new OpenApiSchema {
+ Type = "string",
+ }
+ }
+ },
+ Reference = new OpenApiReference
+ {
+ Id = "myobject",
+ Type = ReferenceType.Schema
+ },
+ UnresolvedReference = false
+ };
+ var document = new OpenApiDocument
+ {
+ Paths = new OpenApiPaths
+ {
+ ["answer"] = new OpenApiPathItem
+ {
+ Operations = {
+ [OperationType.Get] = new OpenApiOperation
+ {
+ Responses = new OpenApiResponses
+ {
+ [statusCode] = new OpenApiResponse {
+ Content = {
+ [contentType] = new OpenApiMediaType {
+ Schema = addModel ? myObjectSchema : null
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+ },
+ Components = new()
+ {
+ Schemas = new Dictionary {
+ {
+ "myobject", myObjectSchema
+ }
+ }
+ }
+ };
+ var mockLogger = new Mock>();
+ var builder = new KiotaBuilder(
+ mockLogger.Object,
+ new GenerationConfiguration
+ {
+ ClientClassName = "TestClient",
+ ClientNamespaceName = "TestSdk",
+ ApiRootUrl = "https://localhost",
+ StructuredMimeTypes = acceptedContentType.Equals("default", StringComparison.OrdinalIgnoreCase) ?
+ new GenerationConfiguration().StructuredMimeTypes :
+ new() { acceptedContentType }
+ }, _httpClient);
+ var node = builder.CreateUriSpace(document);
+ var codeModel = builder.CreateSourceModel(node);
+ var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer");
+ Assert.NotNull(rbNS);
+ var rbClass = rbNS.Classes.FirstOrDefault(x => x.IsOfKind(CodeClassKind.RequestBuilder));
+ Assert.NotNull(rbClass);
+ var executor = rbClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestExecutor));
+ Assert.NotNull(executor);
+ Assert.Equal(returnType, executor.ReturnType.Name);
+ }
+ [InlineData("application/json", true, "default", "myobject")]
+ [InlineData("application/json", false, "default", "binary")]
+ [InlineData("application/xml", false, "default", "binary")]
+ [InlineData("application/xml", true, "default", "binary")] //MyObject when we support it
+ [InlineData("text/xml", false, "default", "binary")]
+ [InlineData("text/xml", true, "default", "binary")] //MyObject when we support it
+ [InlineData("text/yaml", false, "default", "binary")]
+ [InlineData("text/yaml", true, "default", "binary")] //MyObject when we support it
+ [InlineData("application/octet-stream", true, "default", "binary")]
+ [InlineData("application/octet-stream", false, "default", "binary")]
+ [InlineData("text/html", true, "default", "binary")]
+ [InlineData("text/html", false, "default", "binary")]
+ [InlineData("*/*", true, "default", "binary")]
+ [InlineData("*/*", false, "default", "binary")]
+ [InlineData("text/plain", false, "default", "binary")]
+ [InlineData("text/plain", true, "default", "myobject")]
+ [InlineData("text/plain", true, "application/json", "binary")]
+ [InlineData("text/plain", false, "application/json", "binary")]
+ [InlineData("text/yaml", true, "application/json", "binary")]
+ [InlineData("text/yaml", false, "application/json", "binary")]
+ [Theory]
+ public void GeneratesTheRightParameterTypeBasedOnContentAndStatus(string contentType, bool addModel, string acceptedContentType, string parameterType)
+ {
+ var myObjectSchema = new OpenApiSchema
+ {
+ Type = "object",
+ Properties = new Dictionary {
+ {
+ "id", new OpenApiSchema {
+ Type = "string",
+ }
+ }
+ },
+ Reference = new OpenApiReference
+ {
+ Id = "myobject",
+ Type = ReferenceType.Schema
+ },
+ UnresolvedReference = false
+ };
+ var document = new OpenApiDocument
+ {
+ Paths = new OpenApiPaths
+ {
+ ["answer"] = new OpenApiPathItem
+ {
+ Operations = {
+ [OperationType.Post] = new OpenApiOperation
+ {
+ RequestBody = new OpenApiRequestBody {
+ Content = {
+ [contentType] = new OpenApiMediaType {
+ Schema = addModel ? myObjectSchema : null
+ }
+ }
+ },
+ Responses = new OpenApiResponses
+ {
+ ["204"] = new OpenApiResponse(),
+ }
+ }
+ }
+ }
+ },
+ Components = new()
+ {
+ Schemas = new Dictionary {
+ {
+ "myobject", myObjectSchema
+ }
+ }
+ }
+ };
+ var mockLogger = new Mock>();
+ var builder = new KiotaBuilder(
+ mockLogger.Object,
+ new GenerationConfiguration
+ {
+ ClientClassName = "TestClient",
+ ClientNamespaceName = "TestSdk",
+ ApiRootUrl = "https://localhost",
+ StructuredMimeTypes = acceptedContentType.Equals("default", StringComparison.OrdinalIgnoreCase) ?
+ new GenerationConfiguration().StructuredMimeTypes :
+ new() { acceptedContentType }
+ }, _httpClient);
+ var node = builder.CreateUriSpace(document);
+ var codeModel = builder.CreateSourceModel(node);
+ var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer");
+ Assert.NotNull(rbNS);
+ var rbClass = rbNS.Classes.FirstOrDefault(x => x.IsOfKind(CodeClassKind.RequestBuilder));
+ Assert.NotNull(rbClass);
+ var executor = rbClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestExecutor));
+ Assert.NotNull(executor);
+ Assert.Equal(parameterType, executor.Parameters.OfKind(CodeParameterKind.RequestBody).Type.Name);
+ }
+ [Theory]
+ [InlineData("application/json, text/plain", "application/json", "application/json;q=1", "text/plain;q=1")]
+ [InlineData("application/json, text/plain, application/yaml", "application/json;q=0.8,application/yaml;q=1", "application/yaml;q=1,application/json;q=0.8", "text/plain;q=1")]
+ [InlineData("*/*", "application/json;q=0.8", "*/*", "application/json;q=0.8")]
+ [InlineData("application/json, */*", "application/json;q=0.8", "application/json;q=0.8", "*/*")]
+ [InlineData("application/png, application/jpg", "application/json;q=0.8", "application/png, application/jpg", "application/json;q=0.8")]
+ public void GeneratesTheRightAcceptHeaderBasedOnContentAndStatus(string contentMediaTypes, string structuredMimeTypes, string expectedAcceptHeader, string unexpectedMimeTypes)
+ {
+ var document = new OpenApiDocument
+ {
+ Paths = new OpenApiPaths
+ {
+ ["answer"] = new OpenApiPathItem
+ {
+ Operations = {
+ [OperationType.Get] = new OpenApiOperation
+ {
+ Responses = new OpenApiResponses
+ {
+ ["200"] = new OpenApiResponse {
+ Content = contentMediaTypes.Split(',').Select(x => new {Key = x.Trim(), value = new OpenApiMediaType {
+ Schema = new OpenApiSchema {
+ Type = "object",
+ Properties = new Dictionary {
+ {
+ "id", new OpenApiSchema {
+ Type = "string",
+ }
+ }
+ },
+ Reference = new OpenApiReference
+ {
+ Id = "myobject",
+ Type = ReferenceType.Schema
+ },
+ UnresolvedReference = false
+ }
+ }
+ }).ToDictionary(x => x.Key, x => x.value)
+ },
+ }
+ }
+ }
+ }
+ },
+ Components = new()
+ {
+ Schemas = new Dictionary {
+ {
+ "myobject", new OpenApiSchema {
+ Type = "object",
+ Properties = new Dictionary {
+ {
+ "id", new OpenApiSchema {
+ Type = "string",
+ }
+ }
+ },
+ Reference = new OpenApiReference
+ {
+ Id = "myobject",
+ Type = ReferenceType.Schema
+ },
+ UnresolvedReference = false
+ }
+ }
+ }
+ }
+ };
+ var mockLogger = new Mock>();
+ var builder = new KiotaBuilder(
+ mockLogger.Object,
+ new GenerationConfiguration
+ {
+ ClientClassName = "TestClient",
+ ClientNamespaceName = "TestSdk",
+ ApiRootUrl = "https://localhost",
+ StructuredMimeTypes = new(structuredMimeTypes.Split(',').Select(x => x.Trim()))
+ }, _httpClient);
+ var node = builder.CreateUriSpace(document);
+ var codeModel = builder.CreateSourceModel(node);
+ var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer");
+ Assert.NotNull(rbNS);
+ var rbClass = rbNS.Classes.FirstOrDefault(static x => x.IsOfKind(CodeClassKind.RequestBuilder));
+ Assert.NotNull(rbClass);
+ var generator = rbClass.Methods.FirstOrDefault(static x => x.IsOfKind(CodeMethodKind.RequestGenerator));
+ Assert.NotNull(generator);
+ foreach (var header in expectedAcceptHeader.Split(','))
+ Assert.Contains(header.Trim(), generator.AcceptedResponseTypes);
+ foreach (var header in unexpectedMimeTypes.Split(','))
+ Assert.DoesNotContain(header.Trim(), generator.AcceptedResponseTypes);
+ }
+ [Theory]
+ [InlineData("application/json, text/plain", "application/json", "application/json", "text/plain")]
+ [InlineData("application/json, text/plain, application/yaml", "application/json;q=0.8,application/yaml;q=1", "application/yaml", "text/plain")]
+ [InlineData("*/*", "application/json;q=0.8", "", "application/json")]
+ [InlineData("application/json, */*", "application/json;q=0.8", "application/json", "*/*")]
+ [InlineData("application/png, application/jpg", "application/json;q=0.8", "", "application/json")]
+ public void GeneratesTheRightContentTypeHeaderBasedOnContentAndStatus(string contentMediaTypes, string structuredMimeTypes, string expectedContentTypeHeader, string unexpectedMimeTypes)
+ {
+ var document = new OpenApiDocument
+ {
+ Paths = new OpenApiPaths
+ {
+ ["answer"] = new OpenApiPathItem
+ {
+ Operations = {
+ [OperationType.Post] = new OpenApiOperation
+ {
+ RequestBody = new OpenApiRequestBody
+ {
+ Content = contentMediaTypes.Split(',').Select(x => new {Key = x.Trim(), value = new OpenApiMediaType {
+ Schema = new OpenApiSchema {
+ Type = "object",
+ Properties = new Dictionary {
+ {
+ "id", new OpenApiSchema {
+ Type = "string",
+ }
+ }
+ },
+ Reference = new OpenApiReference
+ {
+ Id = "myobject",
+ Type = ReferenceType.Schema
+ },
+ UnresolvedReference = false
+ }
+ }
+ }).ToDictionary(x => x.Key, x => x.value)
+ },
+ }
+ }
+ }
+ },
+ Components = new()
+ {
+ Schemas = new Dictionary {
+ {
+ "myobject", new OpenApiSchema {
+ Type = "object",
+ Properties = new Dictionary {
+ {
+ "id", new OpenApiSchema {
+ Type = "string",
+ }
+ }
+ },
+ Reference = new OpenApiReference
+ {
+ Id = "myobject",
+ Type = ReferenceType.Schema
+ },
+ UnresolvedReference = false
+ }
+ }
+ }
+ }
+ };
+ var mockLogger = new Mock>();
+ var builder = new KiotaBuilder(
+ mockLogger.Object,
+ new GenerationConfiguration
+ {
+ ClientClassName = "TestClient",
+ ClientNamespaceName = "TestSdk",
+ ApiRootUrl = "https://localhost",
+ StructuredMimeTypes = new(structuredMimeTypes.Split(',').Select(x => x.Trim()))
+ }, _httpClient);
+ var node = builder.CreateUriSpace(document);
+ var codeModel = builder.CreateSourceModel(node);
+ var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer");
+ Assert.NotNull(rbNS);
+ var rbClass = rbNS.Classes.FirstOrDefault(static x => x.IsOfKind(CodeClassKind.RequestBuilder));
+ Assert.NotNull(rbClass);
+ var generator = rbClass.Methods.FirstOrDefault(static x => x.IsOfKind(CodeMethodKind.RequestGenerator));
+ Assert.NotNull(generator);
+ if (string.IsNullOrEmpty(expectedContentTypeHeader))
+ {
+ Assert.Empty(generator.RequestBodyContentType);
+ Assert.NotNull(generator.Parameters.OfKind(CodeParameterKind.RequestBodyContentType));
+ }
+ else
+ foreach (var header in expectedContentTypeHeader.Split(','))
+ Assert.Contains(header.Trim(), generator.RequestBodyContentType);
+ foreach (var header in unexpectedMimeTypes.Split(','))
+ Assert.DoesNotContain(header.Trim(), generator.RequestBodyContentType);
+ }
+}
diff --git a/tests/Kiota.Builder.Tests/Extensions/OpenApiOperationExtensionsTests.cs b/tests/Kiota.Builder.Tests/Extensions/OpenApiOperationExtensionsTests.cs
index 892f710189..79114497b6 100644
--- a/tests/Kiota.Builder.Tests/Extensions/OpenApiOperationExtensionsTests.cs
+++ b/tests/Kiota.Builder.Tests/Extensions/OpenApiOperationExtensionsTests.cs
@@ -58,8 +58,7 @@ public void GetsResponseSchema()
public void Defensive()
{
var source = new Dictionary();
- Assert.Empty(source.GetValidSchemas(new HashSet { "application/json" }));
- Assert.Throws(() => source.GetValidSchemas(new HashSet()));
+ Assert.Empty(source.GetValidSchemas(new() { "application/json" }));
Assert.Throws(() => source.GetValidSchemas(null));
}
}
diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
index d69ee88d16..4775493de7 100644
--- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
+++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
@@ -817,8 +817,8 @@ await File.WriteAllTextAsync(tempFilePath, @"openapi: 3.0.1
Assert.NotNull(treeNode);
Assert.Equal("GraphClient", configuration.ClientClassName);
Assert.Equal("Microsoft.Graph", configuration.ClientNamespaceName);
- Assert.Contains("application/json", configuration.StructuredMimeTypes);
- Assert.Contains("application/xml", configuration.StructuredMimeTypes);
+ Assert.Contains("application/json;q=1", configuration.StructuredMimeTypes);
+ Assert.Contains("application/xml;q=1", configuration.StructuredMimeTypes);
_tempFiles.Add(tempFilePath);
}
[Fact]
@@ -4898,132 +4898,6 @@ public void ModelsUseDescriptionWhenAvailable(bool excludeBackwardCompatible)
Assert.Equal("some path item description", responseProperty.Documentation.Description);
}
- [InlineData("application/json", "206", true, "default", "myobject")]
- [InlineData("application/json", "206", false, "default", "binary")]
- [InlineData("application/json", "205", true, "default", "void")]
- [InlineData("application/json", "205", false, "default", "void")]
- [InlineData("application/json", "204", true, "default", "void")]
- [InlineData("application/json", "204", false, "default", "void")]
- [InlineData("application/json", "203", true, "default", "myobject")]
- [InlineData("application/json", "203", false, "default", "binary")]
- [InlineData("application/json", "202", true, "default", "myobject")]
- [InlineData("application/json", "202", false, "default", "void")]
- [InlineData("application/json", "201", true, "default", "myobject")]
- [InlineData("application/json", "201", false, "default", "void")]
- [InlineData("application/json", "200", true, "default", "myobject")]
- [InlineData("application/json", "200", false, "default", "binary")]
- [InlineData("application/json", "2XX", true, "default", "myobject")]
- [InlineData("application/json", "2XX", false, "default", "binary")]
- [InlineData("application/xml", "204", true, "default", "void")]
- [InlineData("application/xml", "204", false, "default", "void")]
- [InlineData("application/xml", "200", true, "default", "binary")] // MyObject when we support xml deserialization
- [InlineData("application/xml", "200", false, "default", "binary")]
- [InlineData("text/xml", "204", true, "default", "void")]
- [InlineData("text/xml", "204", false, "default", "void")]
- [InlineData("text/xml", "200", true, "default", "binary")] // MyObject when we support xml deserialization
- [InlineData("text/xml", "200", false, "default", "binary")]
- [InlineData("text/yaml", "204", true, "default", "void")]
- [InlineData("text/yaml", "204", false, "default", "void")]
- [InlineData("text/yaml", "200", true, "default", "binary")] // MyObject when we support xml deserialization
- [InlineData("text/yaml", "200", false, "default", "binary")]
- [InlineData("application/octet-stream", "204", true, "default", "void")]
- [InlineData("application/octet-stream", "204", false, "default", "void")]
- [InlineData("application/octet-stream", "200", true, "default", "binary")]
- [InlineData("application/octet-stream", "200", false, "default", "binary")]
- [InlineData("text/html", "204", true, "default", "void")]
- [InlineData("text/html", "204", false, "default", "void")]
- [InlineData("text/html", "200", true, "default", "binary")]
- [InlineData("text/html", "200", false, "default", "binary")]
- [InlineData("*/*", "204", true, "default", "void")]
- [InlineData("*/*", "204", false, "default", "void")]
- [InlineData("*/*", "200", true, "default", "binary")]
- [InlineData("*/*", "200", false, "default", "binary")]
- [InlineData("text/plain", "204", true, "default", "void")]
- [InlineData("text/plain", "204", false, "default", "void")]
- [InlineData("text/plain", "200", true, "default", "myobject")]
- [InlineData("text/plain", "200", false, "default", "string")]
- [InlineData("text/plain", "204", true, "application/json", "void")]
- [InlineData("text/plain", "204", false, "application/json", "void")]
- [InlineData("text/plain", "200", true, "application/json", "string")]
- [InlineData("text/plain", "200", false, "application/json", "string")]
- [InlineData("text/yaml", "204", true, "application/json", "void")]
- [InlineData("text/yaml", "204", false, "application/json", "void")]
- [InlineData("text/yaml", "200", true, "application/json", "binary")]
- [InlineData("text/yaml", "200", false, "application/json", "binary")]
- [Theory]
- public void GeneratesTheRightReturnTypeBasedOnContentAndStatus(string contentType, string statusCode, bool addModel, string acceptedContentType, string returnType)
- {
- var myObjectSchema = new OpenApiSchema
- {
- Type = "object",
- Properties = new Dictionary {
- {
- "id", new OpenApiSchema {
- Type = "string",
- }
- }
- },
- Reference = new OpenApiReference
- {
- Id = "myobject",
- Type = ReferenceType.Schema
- },
- UnresolvedReference = false
- };
- var document = new OpenApiDocument
- {
- Paths = new OpenApiPaths
- {
- ["answer"] = new OpenApiPathItem
- {
- Operations = {
- [OperationType.Get] = new OpenApiOperation
- {
- Responses = new OpenApiResponses
- {
- [statusCode] = new OpenApiResponse {
- Content = {
- [contentType] = new OpenApiMediaType {
- Schema = addModel ? myObjectSchema : null
- }
- }
- },
- }
- }
- }
- }
- },
- Components = new()
- {
- Schemas = new Dictionary {
- {
- "myobject", myObjectSchema
- }
- }
- }
- };
- var mockLogger = new Mock>();
- var builder = new KiotaBuilder(
- mockLogger.Object,
- new GenerationConfiguration
- {
- ClientClassName = "TestClient",
- ClientNamespaceName = "TestSdk",
- ApiRootUrl = "https://localhost",
- StructuredMimeTypes = acceptedContentType.Equals("default", StringComparison.OrdinalIgnoreCase) ?
- new GenerationConfiguration().StructuredMimeTypes :
- new(StringComparer.OrdinalIgnoreCase) { acceptedContentType }
- }, _httpClient);
- var node = builder.CreateUriSpace(document);
- var codeModel = builder.CreateSourceModel(node);
- var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer");
- Assert.NotNull(rbNS);
- var rbClass = rbNS.Classes.FirstOrDefault(x => x.IsOfKind(CodeClassKind.RequestBuilder));
- Assert.NotNull(rbClass);
- var executor = rbClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestExecutor));
- Assert.NotNull(executor);
- Assert.Equal(returnType, executor.ReturnType.Name);
- }
[Fact]
public void Considers200WithSchemaOver2XXWithSchema()
{
@@ -5259,101 +5133,6 @@ public void Considers204WithNoSchemaOver206WithNoSchema()
Assert.NotNull(executor);
Assert.Equal("void", executor.ReturnType.Name);
}
- [InlineData("application/json", true, "default", "myobject")]
- [InlineData("application/json", false, "default", "binary")]
- [InlineData("application/xml", false, "default", "binary")]
- [InlineData("application/xml", true, "default", "binary")] //MyObject when we support it
- [InlineData("text/xml", false, "default", "binary")]
- [InlineData("text/xml", true, "default", "binary")] //MyObject when we support it
- [InlineData("text/yaml", false, "default", "binary")]
- [InlineData("text/yaml", true, "default", "binary")] //MyObject when we support it
- [InlineData("application/octet-stream", true, "default", "binary")]
- [InlineData("application/octet-stream", false, "default", "binary")]
- [InlineData("text/html", true, "default", "binary")]
- [InlineData("text/html", false, "default", "binary")]
- [InlineData("*/*", true, "default", "binary")]
- [InlineData("*/*", false, "default", "binary")]
- [InlineData("text/plain", false, "default", "binary")]
- [InlineData("text/plain", true, "default", "myobject")]
- [InlineData("text/plain", true, "application/json", "binary")]
- [InlineData("text/plain", false, "application/json", "binary")]
- [InlineData("text/yaml", true, "application/json", "binary")]
- [InlineData("text/yaml", false, "application/json", "binary")]
- [Theory]
- public void GeneratesTheRightParameterTypeBasedOnContentAndStatus(string contentType, bool addModel, string acceptedContentType, string parameterType)
- {
- var myObjectSchema = new OpenApiSchema
- {
- Type = "object",
- Properties = new Dictionary {
- {
- "id", new OpenApiSchema {
- Type = "string",
- }
- }
- },
- Reference = new OpenApiReference
- {
- Id = "myobject",
- Type = ReferenceType.Schema
- },
- UnresolvedReference = false
- };
- var document = new OpenApiDocument
- {
- Paths = new OpenApiPaths
- {
- ["answer"] = new OpenApiPathItem
- {
- Operations = {
- [OperationType.Post] = new OpenApiOperation
- {
- RequestBody = new OpenApiRequestBody {
- Content = {
- [contentType] = new OpenApiMediaType {
- Schema = addModel ? myObjectSchema : null
- }
- }
- },
- Responses = new OpenApiResponses
- {
- ["204"] = new OpenApiResponse(),
- }
- }
- }
- }
- },
- Components = new()
- {
- Schemas = new Dictionary {
- {
- "myobject", myObjectSchema
- }
- }
- }
- };
- var mockLogger = new Mock>();
- var builder = new KiotaBuilder(
- mockLogger.Object,
- new GenerationConfiguration
- {
- ClientClassName = "TestClient",
- ClientNamespaceName = "TestSdk",
- ApiRootUrl = "https://localhost",
- StructuredMimeTypes = acceptedContentType.Equals("default", StringComparison.OrdinalIgnoreCase) ?
- new GenerationConfiguration().StructuredMimeTypes :
- new(StringComparer.OrdinalIgnoreCase) { acceptedContentType }
- }, _httpClient);
- var node = builder.CreateUriSpace(document);
- var codeModel = builder.CreateSourceModel(node);
- var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer");
- Assert.NotNull(rbNS);
- var rbClass = rbNS.Classes.FirstOrDefault(x => x.IsOfKind(CodeClassKind.RequestBuilder));
- Assert.NotNull(rbClass);
- var executor = rbClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestExecutor));
- Assert.NotNull(executor);
- Assert.Equal(parameterType, executor.Parameters.OfKind(CodeParameterKind.RequestBody).Type.Name);
- }
[Fact]
public void DoesntGenerateVoidExecutorOnMixed204()
{
@@ -7046,7 +6825,7 @@ public async Task SupportsMultiPartFormAsRequestBody()
Assert.NotNull(rbClass);
var postMethod = rbClass.FindChildByName("Post", false);
Assert.NotNull(postMethod);
- var bodyParameter = postMethod.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.RequestBody));
+ var bodyParameter = postMethod.Parameters.FirstOrDefault(static x => x.IsOfKind(CodeParameterKind.RequestBody));
Assert.NotNull(bodyParameter);
Assert.Equal("MultipartBody", bodyParameter.Type.Name, StringComparer.OrdinalIgnoreCase);
var addressClass = codeModel.FindChildByName("Address");
diff --git a/tests/Kiota.Builder.Tests/CodeDOM/CodeElementComparerPythonTests.cs b/tests/Kiota.Builder.Tests/OrderComparers/CodeElementComparerPythonTests.cs
similarity index 96%
rename from tests/Kiota.Builder.Tests/CodeDOM/CodeElementComparerPythonTests.cs
rename to tests/Kiota.Builder.Tests/OrderComparers/CodeElementComparerPythonTests.cs
index 717306bb37..4c457e7448 100644
--- a/tests/Kiota.Builder.Tests/CodeDOM/CodeElementComparerPythonTests.cs
+++ b/tests/Kiota.Builder.Tests/OrderComparers/CodeElementComparerPythonTests.cs
@@ -2,9 +2,10 @@
using System.Collections.Generic;
using Kiota.Builder.CodeDOM;
+using Kiota.Builder.OrderComparers;
using Xunit;
-namespace Kiota.Builder.Tests.CodeDOM;
+namespace Kiota.Builder.Tests.OrderComparers;
public class CodeElementComparerPythonTests
{
[Fact]
diff --git a/tests/Kiota.Builder.Tests/CodeDOM/CodeElementComparerTests.cs b/tests/Kiota.Builder.Tests/OrderComparers/CodeElementComparerTests.cs
similarity index 98%
rename from tests/Kiota.Builder.Tests/CodeDOM/CodeElementComparerTests.cs
rename to tests/Kiota.Builder.Tests/OrderComparers/CodeElementComparerTests.cs
index efac713cdf..8f1e2a0570 100644
--- a/tests/Kiota.Builder.Tests/CodeDOM/CodeElementComparerTests.cs
+++ b/tests/Kiota.Builder.Tests/OrderComparers/CodeElementComparerTests.cs
@@ -2,9 +2,10 @@
using System.Collections.Generic;
using Kiota.Builder.CodeDOM;
+using Kiota.Builder.OrderComparers;
using Xunit;
-namespace Kiota.Builder.Tests.CodeDOM;
+namespace Kiota.Builder.Tests.OrderComparers;
public class CodeElementComparerTests
{
[Fact]
diff --git a/tests/Kiota.Builder.Tests/CodeDOM/CodeParameterOrderComparerTests.cs b/tests/Kiota.Builder.Tests/OrderComparers/CodeParameterOrderComparerTests.cs
similarity index 98%
rename from tests/Kiota.Builder.Tests/CodeDOM/CodeParameterOrderComparerTests.cs
rename to tests/Kiota.Builder.Tests/OrderComparers/CodeParameterOrderComparerTests.cs
index fd1f3142a5..5329f1c003 100644
--- a/tests/Kiota.Builder.Tests/CodeDOM/CodeParameterOrderComparerTests.cs
+++ b/tests/Kiota.Builder.Tests/OrderComparers/CodeParameterOrderComparerTests.cs
@@ -2,6 +2,7 @@
using System.Linq;
using Kiota.Builder.CodeDOM;
+using Kiota.Builder.OrderComparers;
using Kiota.Builder.Writers.Go;
using Kiota.Builder.Writers.Python;
@@ -9,7 +10,7 @@
using Xunit;
-namespace Kiota.Builder.Tests.CodeDOM;
+namespace Kiota.Builder.Tests.OrderComparers;
public class CodeParameterOrderComparerTests
{
[Fact]
diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
index d55e5dcfe3..16945ceff1 100644
--- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
@@ -1021,6 +1021,56 @@ public void WritesRequestGeneratorBodyForScalarCollection()
AssertExtensions.CurlyBracesAreClosed(result, 1);
}
[Fact]
+ public void WritesRequestGeneratorBodyKnownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new CSharpConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.RequestBodyContentType = "application/json";
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("SetStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result, 1);
+ }
+ [Fact]
+ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new CSharpConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.AddParameter(new CodeParameter
+ {
+ Name = "requestContentType",
+ Type = new CodeType()
+ {
+ Name = "string",
+ IsExternal = true,
+ },
+ Kind = CodeParameterKind.RequestBodyContentType,
+ });
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("SetStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(", requestContentType", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result, 1);
+ }
+ [Fact]
public void WritesInheritedDeSerializerBody()
{
setup(true);
diff --git a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs
index 117d50adf9..769f9555d0 100644
--- a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs
@@ -1293,6 +1293,56 @@ public async Task WritesRequestGeneratorBodyForParsableCollection()
AssertExtensions.CurlyBracesAreClosed(result);
}
[Fact]
+ public void WritesRequestGeneratorBodyKnownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(useComplexTypeForBody: false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new GoConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.RequestBodyContentType = "application/json";
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("SetStreamContentAndContentType", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
+ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(useComplexTypeForBody: false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new GoConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.AddParameter(new CodeParameter
+ {
+ Name = "requestContentType",
+ Type = new CodeType()
+ {
+ Name = "string",
+ IsExternal = true,
+ },
+ Kind = CodeParameterKind.RequestBodyContentType,
+ });
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("SetStreamContentAndContentType", result, StringComparison.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(", requestContentType", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
public void WritesInheritedDeSerializerBody()
{
setup(true);
diff --git a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs
index b50fdc0d87..7e4fcc9a16 100644
--- a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs
@@ -1328,6 +1328,56 @@ public void WritesIntersectionDeSerializerBody()
AssertExtensions.CurlyBracesAreClosed(result);
}
[Fact]
+ public void WritesRequestGeneratorBodyKnownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new JavaConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.RequestBodyContentType = "application/json";
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("setStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
+ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new JavaConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.AddParameter(new CodeParameter
+ {
+ Name = "requestContentType",
+ Type = new CodeType()
+ {
+ Name = "string",
+ IsExternal = true,
+ },
+ Kind = CodeParameterKind.RequestBodyContentType,
+ });
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("setStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(", requestContentType", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
public void WritesInheritedDeSerializerBody()
{
setup(true);
diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs
index 6650e1a924..c0f8cd3783 100644
--- a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs
@@ -941,6 +941,56 @@ public void WritesUnionDeSerializerBody()
AssertExtensions.CurlyBracesAreClosed(result);
}
[Fact]
+ public void WritesRequestGeneratorBodyKnownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters();
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new PhpConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.RequestBodyContentType = "application/json";
+ languageWriter.Write(method);
+ var result = stringWriter.ToString();
+ Assert.Contains("setStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
+ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters();
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new PhpConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.AddParameter(new CodeParameter
+ {
+ Name = "requestContentType",
+ Type = new CodeType()
+ {
+ Name = "string",
+ IsExternal = true,
+ },
+ Kind = CodeParameterKind.RequestBodyContentType,
+ });
+ languageWriter.Write(method);
+ var result = stringWriter.ToString();
+ Assert.Contains("setStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(", $requestContentType", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
public void WritesIntersectionDeSerializerBody()
{
setup();
diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs
index a17efa9aab..82ca6a77cc 100644
--- a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs
@@ -707,6 +707,56 @@ public void WritesRequestGeneratorBodyForParsable()
Assert.Contains("return request_info", result);
}
[Fact]
+ public void WritesRequestGeneratorBodyKnownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new PythonConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.RequestBodyContentType = "application/json";
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("set_stream_content", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
+ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new PythonConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.AddParameter(new CodeParameter
+ {
+ Name = "request_content_type",
+ Type = new CodeType()
+ {
+ Name = "string",
+ IsExternal = true,
+ },
+ Kind = CodeParameterKind.RequestBodyContentType,
+ });
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("set_stream_content", result, StringComparison.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(", request_content_type", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
public void WritesInheritedDeSerializerBody()
{
setup(true);
diff --git a/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs
index f08ac02348..0867495221 100644
--- a/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs
@@ -508,7 +508,7 @@ public void WritesRequestGeneratorBody()
setup();
method.Kind = CodeMethodKind.RequestGenerator;
method.HttpMethod = HttpMethod.Get;
- method.AcceptedResponseTypes = new() { "application/json" };
+ method.AcceptedResponseTypes.Add("application/json");
AddRequestProperties();
AddRequestBodyParameters();
writer.Write(method);
@@ -525,6 +525,56 @@ public void WritesRequestGeneratorBody()
Assert.Contains("return request_info", result);
}
[Fact]
+ public void WritesRequestGeneratorBodyKnownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters();
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new RubyConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.RequestBodyContentType = "application/json";
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("set_stream_content", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
+ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
+ {
+ setup();
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters();
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new RubyConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.AddParameter(new CodeParameter
+ {
+ Name = "request_content_type",
+ Type = new CodeType()
+ {
+ Name = "string",
+ IsExternal = true,
+ },
+ Kind = CodeParameterKind.RequestBodyContentType,
+ });
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("set_stream_content", result, StringComparison.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(", request_content_type", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
public void WritesInheritedDeSerializerBody()
{
setup(true);
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs
index b166f292b0..d6efa5487d 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs
@@ -5,6 +5,7 @@
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Configuration;
using Kiota.Builder.Extensions;
+using Kiota.Builder.OrderComparers;
using Kiota.Builder.Refiners;
using Kiota.Builder.Writers;
using Xunit;
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs
index 47babf4fca..2d1dcf134d 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs
@@ -308,6 +308,62 @@ public async Task WritesRequestGeneratorBodyForParsable()
Assert.Contains("return requestInfo;", result);
AssertExtensions.CurlyBracesAreClosed(result);
}
+ [Fact]
+ public void WritesRequestGeneratorBodyKnownRequestBodyType()
+ {
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Get;
+ AddRequestProperties();
+ AddRequestBodyParameters(true);
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new TypeScriptConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.RequestBodyContentType = "application/json";
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("setStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains("application/json", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
+ [Fact]
+ public void WritesRequestGeneratorBodyUnknownRequestBodyType()
+ {
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Get;
+ AddRequestProperties();
+ AddRequestBodyParameters(true);
+ method.Kind = CodeMethodKind.RequestGenerator;
+ method.HttpMethod = HttpMethod.Post;
+ AddRequestProperties();
+ AddRequestBodyParameters(false);
+ method.Parameters.OfKind(CodeParameterKind.RequestBody).Type = new CodeType
+ {
+ Name = new TypeScriptConventionService().StreamTypeName,
+ IsExternal = true,
+ };
+ method.AddParameter(new CodeParameter
+ {
+ Name = "requestContentType",
+ Type = new CodeType()
+ {
+ Name = "string",
+ IsExternal = true,
+ },
+ Kind = CodeParameterKind.RequestBodyContentType,
+ });
+ writer.Write(method);
+ var result = tw.ToString();
+ Assert.Contains("setStreamContent", result, StringComparison.OrdinalIgnoreCase);
+ Assert.DoesNotContain("application/json", result, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(", requestContentType", result, StringComparison.OrdinalIgnoreCase);
+ AssertExtensions.CurlyBracesAreClosed(result);
+ }
[Fact]
public void WritesMethodAsyncDescription()