-
Notifications
You must be signed in to change notification settings - Fork 306
Provide an error message from Open api description #6953
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
bfc848a
1c3d3e8
b4c5f47
9bd10a8
3d40934
2131100
e287fd2
19491e5
159e96a
5856ca0
425f81c
353c1ba
c9b42ee
3e226d6
5c7a961
cee1363
e77d204
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -254,6 +254,7 @@ public void DeduplicateErrorMappings() | |
| public bool HasUrlTemplateOverride => !string.IsNullOrEmpty(UrlTemplateOverride); | ||
|
|
||
| private ConcurrentDictionary<string, CodeTypeBase> errorMappings = new(StringComparer.OrdinalIgnoreCase); | ||
| private ConcurrentDictionary<string, string> errorDescriptions = new(StringComparer.OrdinalIgnoreCase); | ||
|
|
||
| /// <summary> | ||
| /// Mapping of the error code and response types for this method. | ||
|
|
@@ -265,6 +266,17 @@ public IOrderedEnumerable<KeyValuePair<string, CodeTypeBase>> ErrorMappings | |
| return errorMappings.OrderBy(static x => x.Key); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Mapping of the error code and response descriptions from OpenAPI spec for this method. | ||
| /// </summary> | ||
| public IOrderedEnumerable<KeyValuePair<string, string>> ErrorDescriptions | ||
| { | ||
| get | ||
| { | ||
| return errorDescriptions.OrderBy(static x => x.Key); | ||
| } | ||
| } | ||
| public bool HasErrorMappingCode(string code) | ||
| { | ||
| ArgumentException.ThrowIfNullOrEmpty(code); | ||
|
|
@@ -304,6 +316,7 @@ public object Clone() | |
| Parent = Parent, | ||
| OriginalIndexer = OriginalIndexer, | ||
| errorMappings = new(errorMappings), | ||
| errorDescriptions = new(errorDescriptions), | ||
koen-lee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| AcceptedResponseTypes = new List<string>(AcceptedResponseTypes), | ||
| PagingInformation = PagingInformation?.Clone() as PagingInformation, | ||
| Documentation = (CodeDocumentation)Documentation.Clone(), | ||
|
|
@@ -330,4 +343,20 @@ public void AddErrorMapping(string errorCode, CodeTypeBase type) | |
| ArgumentException.ThrowIfNullOrEmpty(errorCode); | ||
| errorMappings.TryAdd(errorCode, type); | ||
| } | ||
|
|
||
| public void AddErrorMapping(string errorCode, CodeTypeBase type, string description) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(type); | ||
| ArgumentException.ThrowIfNullOrEmpty(errorCode); | ||
| errorMappings.TryAdd(errorCode, type); | ||
| if (!string.IsNullOrEmpty(description)) | ||
|
||
| errorDescriptions.TryAdd(errorCode, description); | ||
| } | ||
|
|
||
| public string? GetErrorDescription(string errorCode) | ||
| { | ||
| ArgumentException.ThrowIfNullOrEmpty(errorCode); | ||
| errorDescriptions.TryGetValue(errorCode, out var description); | ||
| return description; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| using Kiota.Builder.OrderComparers; | ||
|
|
||
| namespace Kiota.Builder.Writers.CSharp; | ||
|
|
||
| public class CodeMethodWriter : BaseElementWriter<CodeMethod, CSharpConventionService> | ||
| { | ||
| public CodeMethodWriter(CSharpConventionService conventionService) : base(conventionService) | ||
|
|
@@ -203,6 +204,15 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas | |
| WriteFactoryMethodBodyForUnionModel(codeElement, parentClass, parseNodeParameter, writer); | ||
| else if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForIntersectionType) | ||
| WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer); | ||
| else if (codeElement.Name == "CreateFromDiscriminatorValueWithMessage" && parentClass.IsErrorDefinition) | ||
| { | ||
| // Special case: CreateFromDiscriminatorValueWithMessage for error classes | ||
| var messageParam = codeElement.Parameters.FirstOrDefault(p => p.Name == "message"); | ||
koen-lee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (messageParam != null) | ||
| writer.WriteLine($"return new {parentClass.GetFullName()}({messageParam.Name});"); | ||
| else | ||
| writer.WriteLine($"return new {parentClass.GetFullName()}();"); | ||
| } | ||
| else | ||
| writer.WriteLine($"return new {parentClass.GetFullName()}();"); | ||
| } | ||
|
|
@@ -401,7 +411,21 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re | |
| writer.StartBlock(); | ||
| foreach (var errorMapping in codeElement.ErrorMappings.Where(errorMapping => errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass)) | ||
| { | ||
| writer.WriteLine($"{{ \"{errorMapping.Key.ToUpperInvariant()}\", {conventions.GetTypeString(errorMapping.Value, codeElement, false)}.CreateFromDiscriminatorValue }},"); | ||
| var errorClass = errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition as CodeClass; | ||
koen-lee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| var typeName = conventions.GetTypeString(errorMapping.Value, codeElement, false); | ||
|
|
||
| if (errorClass?.IsErrorDefinition == true) | ||
| { | ||
| var errorDescription = codeElement.GetErrorDescription(errorMapping.Key); | ||
| var statusCodeAndDescription = !string.IsNullOrEmpty(errorDescription) | ||
|
||
| ? $"{errorMapping.Key} {errorDescription}" | ||
| : errorMapping.Key; | ||
| writer.WriteLine($"{{ \"{errorMapping.Key.ToUpperInvariant()}\", (parseNode) => {typeName}.CreateFromDiscriminatorValueWithMessage(parseNode, \"{statusCodeAndDescription}\") }},"); | ||
| } | ||
| else | ||
| { | ||
| writer.WriteLine($"{{ \"{errorMapping.Key.ToUpperInvariant()}\", {typeName}.CreateFromDiscriminatorValue }},"); | ||
| } | ||
| } | ||
| writer.CloseBlock("};"); | ||
| } | ||
|
|
@@ -608,9 +632,17 @@ private static string GetBaseSuffix(bool isConstructor, bool inherits, CodeClass | |
| } | ||
| return " : base()"; | ||
| } | ||
| // For error classes with message constructor, pass the message to base constructor | ||
| else if (isConstructor && parentClass.IsErrorDefinition && | ||
| currentMethod.Parameters.Any(p => p.Name.Equals("message", StringComparison.OrdinalIgnoreCase) && | ||
koen-lee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| p.Type.Name.Equals("string", StringComparison.OrdinalIgnoreCase))) | ||
| { | ||
| return " : base(message)"; | ||
| } | ||
|
|
||
| return string.Empty; | ||
| } | ||
|
|
||
| private void WriteMethodPrototype(CodeMethod code, CodeClass parentClass, LanguageWriter writer, string returnType, bool inherits, bool isVoid) | ||
| { | ||
| var staticModifier = code.IsStatic ? "static " : string.Empty; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -961,5 +961,84 @@ public async Task SetTypeAccessModifierAsync(AccessModifier accessModifier) | |
| Assert.Equal(codeClass.Access, accessModifier); | ||
| Assert.Equal(codeEnum.Access, accessModifier); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task AddsMessageConstructorToErrorClasses() | ||
| { | ||
| // Given | ||
| var errorClass = root.AddClass(new CodeClass | ||
| { | ||
| Name = "Error401", | ||
| IsErrorDefinition = true | ||
| }).First(); | ||
|
|
||
| // When | ||
| await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.CSharp }, root); | ||
|
|
||
| // Then | ||
| var messageConstructor = errorClass.Methods | ||
| .FirstOrDefault(m => m.IsOfKind(CodeMethodKind.Constructor) && | ||
| m.Parameters.Any(p => p.Type.Name.Equals("string", StringComparison.OrdinalIgnoreCase) && p.Name.Equals("message", StringComparison.OrdinalIgnoreCase))); | ||
|
||
|
|
||
| Assert.NotNull(messageConstructor); | ||
| Assert.Single(messageConstructor.Parameters); | ||
| Assert.Equal("message", messageConstructor.Parameters.First().Name); | ||
| Assert.Equal("string", messageConstructor.Parameters.First().Type.Name); | ||
| Assert.False(messageConstructor.Parameters.First().Optional); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task DoesNotAddMessageConstructorToNonErrorClasses() | ||
| { | ||
| // Given | ||
| var regularClass = root.AddClass(new CodeClass | ||
| { | ||
| Name = "RegularModel", | ||
| IsErrorDefinition = false | ||
| }).First(); | ||
|
|
||
| // When | ||
| await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.CSharp }, root); | ||
|
|
||
| // Then | ||
| var messageConstructor = regularClass.Methods | ||
| .FirstOrDefault(m => m.IsOfKind(CodeMethodKind.Constructor) && | ||
| m.Parameters.Any(p => p.Type.Name.Equals("string", StringComparison.OrdinalIgnoreCase) && p.Name.Equals("message", StringComparison.OrdinalIgnoreCase))); | ||
|
|
||
| Assert.Null(messageConstructor); | ||
| } | ||
|
|
||
| [Fact] | ||
| public async Task AddsMessageFactoryMethodToErrorClasses() | ||
| { | ||
| // Given | ||
| var errorClass = root.AddClass(new CodeClass | ||
| { | ||
| Name = "Error401", | ||
| IsErrorDefinition = true | ||
| }).First(); | ||
|
|
||
| // When | ||
| await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.CSharp }, root); | ||
|
|
||
| // Then | ||
| var messageFactoryMethod = errorClass.Methods | ||
| .FirstOrDefault(m => m.IsOfKind(CodeMethodKind.Factory) && | ||
| m.Name.Equals("CreateFromDiscriminatorValueWithMessage", StringComparison.OrdinalIgnoreCase)); | ||
|
|
||
| Assert.NotNull(messageFactoryMethod); | ||
| Assert.Equal(2, messageFactoryMethod.Parameters.Count()); | ||
|
|
||
| var parseNodeParam = messageFactoryMethod.Parameters.FirstOrDefault(p => p.Name.Equals("parseNode", StringComparison.OrdinalIgnoreCase)); | ||
| Assert.NotNull(parseNodeParam); | ||
| Assert.Equal("IParseNode", parseNodeParam.Type.Name); | ||
|
|
||
| var messageParam = messageFactoryMethod.Parameters.FirstOrDefault(p => p.Name.Equals("message", StringComparison.OrdinalIgnoreCase)); | ||
| Assert.NotNull(messageParam); | ||
| Assert.Equal("string", messageParam.Type.Name); | ||
|
|
||
| Assert.True(messageFactoryMethod.IsStatic); | ||
| Assert.Equal(AccessModifier.Public, messageFactoryMethod.Access); | ||
| } | ||
| #endregion | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.