diff --git a/CHANGELOG.md b/CHANGELOG.md index fe3d0ebe85..808528597a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added support for OpenAPI 3.2.0 +- Added HTTP status code to API exception messages by default for all languages except TypeScript ### Changed diff --git a/src/Kiota.Builder/Refiners/GoRefiner.cs b/src/Kiota.Builder/Refiners/GoRefiner.cs index b7c2e93589..7dbcf9adbd 100644 --- a/src/Kiota.Builder/Refiners/GoRefiner.cs +++ b/src/Kiota.Builder/Refiners/GoRefiner.cs @@ -117,9 +117,6 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken true, false, true); - AddDefaultImports( - generatedCode, - defaultUsingEvaluators); CorrectCoreType( generatedCode, CorrectMethodType, @@ -218,6 +215,9 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken "Error", () => new CodeType { Name = "string", IsNullable = false, IsExternal = true } ); + AddDefaultImports( + generatedCode, + defaultUsingEvaluators); GenerateCodeFiles(generatedCode); }, cancellationToken); } @@ -821,6 +821,7 @@ x.Type is CodeType pType && new (static x => x is CodeMethod @method && @method.IsOfKind(CodeMethodKind.RequestExecutor) && (method.ReturnType.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase) || method.Parameters.Any(x => x.Kind is CodeParameterKind.RequestBody && x.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase))), SerializationNamespaceName, KiotaBuilder.UntypedNodeName), + new (static x => x is CodeMethod method && method.IsOfKind(CodeMethodKind.ErrorMessageOverride), "fmt", "*fmt"), new (static x => x is CodeEnum @enum && @enum.Flags,"", "math"), }; private const string MultipartBodyClassName = "MultipartBody"; diff --git a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs index 96a851ff3e..654f6c45a9 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodePropertyWriter.cs @@ -63,7 +63,7 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ if (parentClass.GetPrimaryMessageCodePath(static x => x.Name.ToFirstCharacterUpperCase(), static x => x.Name.ToFirstCharacterUpperCase(), "?.") is string primaryMessageCodePath && !string.IsNullOrEmpty(primaryMessageCodePath)) writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => {primaryMessageCodePath} ?? string.Empty; }}"); else - writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => base.Message; }}"); + writer.WriteLine($"public override {propertyType} {codeElement.Name.ToFirstCharacterUpperCase()} {{ get => $\"{{ResponseStatusCode}}: {{base.Message}}\"; }}"); break; case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped: writer.WriteLine($"[QueryParameter(\"{codeElement.SerializationName}\")]"); diff --git a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs index e3024724c8..7921789736 100644 --- a/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Dart/CodePropertyWriter.cs @@ -60,7 +60,8 @@ private void WritePropertyInternal(CodeProperty codeElement, LanguageWriter writ break; case CodePropertyKind.ErrorMessageOverride when parentClass.IsErrorDefinition: writer.WriteLine("@override"); - goto default; + writer.WriteLine($"{propertyType} get {codeElement.Name} => '$responseStatusCode: ${{super.message}}';"); + break; case CodePropertyKind.QueryParameter when codeElement.IsNameEscaped: writer.WriteLine($"/// @QueryParameter('{codeElement.SerializationName}')"); goto default; diff --git a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs index 479f7e01a3..e2658a50f5 100644 --- a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs @@ -102,7 +102,7 @@ private static void WriteErrorMethodOverride(CodeClass parentClass, LanguageWrit } else { - writer.WriteLine("return m.ApiError.Error()"); + writer.WriteLine("return fmt.Sprintf(\"%d: %s\", m.ResponseStatusCode, m.ApiError.Error())"); } } private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs index ca9385f3db..781394b33c 100644 --- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs @@ -106,7 +106,7 @@ private static void WriteErrorMethodOverride(CodeClass parentClass, LanguageWrit } else { - writer.WriteLine("return super.getMessage();"); + writer.WriteLine("return getResponseStatusCode() + \": \" + super.getMessage();"); } } private void WriteRawUrlBuilderBody(CodeClass parentClass, CodeMethod codeElement, LanguageWriter writer) diff --git a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs index 1270a62541..b44c2251e1 100644 --- a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs @@ -99,7 +99,7 @@ private void WriteErrorMessageOverride(CodeClass parentClass, LanguageWriter wri } else { - writer.WriteLine("return parent::getMessage();"); + writer.WriteLine("return $this->getResponseStatusCode() . ': ' . parent::getMessage();"); } } private const string UrlTemplateTempVarName = "$urlTplParams"; diff --git a/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs index 4e5c40cebd..8f96fb00f3 100644 --- a/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs @@ -65,7 +65,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w writer.WriteLine("return ''"); } else - writer.WriteLine("return super().message"); + writer.WriteLine("return f'{self.response_status_code}: {super().message}'"); writer.DecreaseIndent(); break; } diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs index 52489065f3..67b1c55344 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodePropertyWriterTests.cs @@ -250,5 +250,29 @@ public void WritesMessageOverrideOnPrimary() // Then Assert.Contains("public override string Message { get => Prop1 ?? string.Empty; }", result); } + + [Fact] + public void WritesMessageOverrideWithStatusCodeWhenNoPrimaryMessage() + { + // Given + parentClass.IsErrorDefinition = true; + // No primary error message property added + var overrideProperty = parentClass.AddProperty(new CodeProperty + { + Name = "Message", + Kind = CodePropertyKind.ErrorMessageOverride, + Type = new CodeType + { + Name = "string", + }, + }).First(); + + // When + writer.Write(overrideProperty); + var result = tw.ToString(); + + // Then + Assert.Contains("public override string Message { get => $\"{ResponseStatusCode}: {base.Message}\"; }", result); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs index 8aee37bacc..ec4a5d4b1e 100644 --- a/tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Dart/CodePropertyWriterTests.cs @@ -132,4 +132,15 @@ public void DoesntWritePropertiesExistingInParentType() var result = tw.ToString(); Assert.Empty(result); } + + [Fact] + public void WriteErrorMessageOverrideWithStatusCodeWhenNoPrimary() + { + property.Kind = CodePropertyKind.ErrorMessageOverride; + parentClass.IsErrorDefinition = true; + writer.Write(property); + var result = tw.ToString(); + Assert.Contains("@override", result); + Assert.Contains("get propertyName => '$responseStatusCode: ${super.message}';", result); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs index ca98e97656..36e04376d6 100644 --- a/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Go/CodeMethodWriterTests.cs @@ -2305,6 +2305,71 @@ public void WritesMessageOverrideOnPrimary() Assert.Contains("return *(m.GetProp1()", result); } + [Fact] + public void WritesMessageOverrideWithStatusCodeWhenNoPrimary() + { + // Given + parentClass = root.AddClass(new CodeClass + { + Name = "parentClass", + IsErrorDefinition = true, + Kind = CodeClassKind.Model, + }).First(); + // No primary error message property added + var method = parentClass.AddMethod(new CodeMethod + { + Kind = CodeMethodKind.ErrorMessageOverride, + ReturnType = new CodeType + { + Name = "string", + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, + Name = "Error" + }).First(); + + // When + writer.Write(method); + var result = tw.ToString(); + + // Then + Assert.Contains("Error()(string) {", result); + Assert.Contains("return fmt.Sprintf(\"%d: %s\", m.ResponseStatusCode, m.ApiError.Error())", result); + } + + [Fact] + public async Task AddsFormatImportForErrorMessageOverride() + { + // Given + parentClass = root.AddClass(new CodeClass + { + Name = "parentClass", + IsErrorDefinition = true, + Kind = CodeClassKind.Model, + }).First(); + var method = parentClass.AddMethod(new CodeMethod + { + Kind = CodeMethodKind.ErrorMessageOverride, + ReturnType = new CodeType + { + Name = "string", + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, + Name = "Error" + }).First(); + + // When - Run refiner to add imports + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Go }, root); + + // Then - Verify fmt import was added by the refiner + var fmtUsing = parentClass.StartBlock.Usings.FirstOrDefault(u => u.Declaration?.Name == "fmt"); + Assert.NotNull(fmtUsing); + Assert.Equal("*fmt", fmtUsing.Name); + } + [Fact] public void WritesRequestGeneratorAcceptHeaderQuotes() { diff --git a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs index 5f21b81ff2..fba4027ec7 100644 --- a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs @@ -2166,6 +2166,40 @@ public void WritesMessageOverrideOnPrimary() Assert.Contains("return this.getProp1()", result); } + [Fact] + public void WritesMessageOverrideWithStatusCodeWhenNoPrimary() + { + // Given + parentClass = root.AddClass(new CodeClass + { + Name = "parentClass", + IsErrorDefinition = true, + Kind = CodeClassKind.Model, + }).First(); + // No primary error message property added + var method = parentClass.AddMethod(new CodeMethod + { + Kind = CodeMethodKind.ErrorMessageOverride, + ReturnType = new CodeType + { + Name = "String", + IsNullable = false, + }, + IsAsync = false, + IsStatic = false, + Name = "getErrorMessage" + }).First(); + + // When + writer.Write(method); + var result = tw.ToString(); + + // Then + Assert.Contains("@Override", result); + Assert.Contains("String getErrorMessage() ", result); + Assert.Contains("return getResponseStatusCode() + \": \" + super.getMessage();", result); + } + [Fact] public void WritesRequestGeneratorAcceptHeaderQuotes() { diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs index fdf000c00e..b36684a523 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs @@ -319,6 +319,32 @@ public async Task WriteErrorMessageOverrideAsync() Assert.Contains("return $primaryError->getMessage() ?? '';", result); } + + [Fact] + public async Task WriteErrorMessageOverrideWithStatusCodeWhenNoPrimaryAsync() + { + setup(); + var error401 = root.AddClass(new CodeClass + { + Name = "Error401", + IsErrorDefinition = true + }).First(); + // No primary error message property added + + var codeMethod = new CodeMethod + { + Kind = CodeMethodKind.ErrorMessageOverride, + ReturnType = new CodeType { Name = "string" }, + SimpleName = "getPrimaryErrorMessage", + }; + error401.AddMethod(codeMethod); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.PHP }, root); + _codeMethodWriter.WriteCodeElement(codeMethod, languageWriter); + var result = stringWriter.ToString(); + + Assert.Contains("return $this->getResponseStatusCode() . ': ' . parent::getMessage();", result); + } + [Fact] public async Task WritesRequestExecutorForEnumTypesAsync() { diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs index ce0163df05..b410a8ef73 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodePropertyWriterTests.cs @@ -132,6 +132,17 @@ public void WritePrimaryErrorMessagePropertyOption1() var result = tw.ToString(); Assert.Contains("super().message", result); } + + [Fact] + public void WriteMessageOverrideWithStatusCodeWhenNoPrimary() + { + property.Kind = CodePropertyKind.ErrorMessageOverride; + parentClass.IsErrorDefinition = true; + writer.Write(property); + var result = tw.ToString(); + Assert.Contains("return f'{self.response_status_code}: {super().message}'", result); + } + [Fact] public void WritePrimaryErrorMessagePropertyOption2() {