Skip to content

Conversation

@koen-lee
Copy link

@koen-lee koen-lee commented Sep 25, 2025

See also #4349; this PR aims to change the developer experience from

ApiSdk.Models.ProblemDetails:Exception of type 'ApiSdk.Models.ProblemDetails' was thrown.
         at Microsoft.Kiota.Http.HttpClientLibrary.HttpClientRequestAdapter.ThrowIfFailedResponse....

to

ApiSdk.Models.ProblemDetails:403 Client certificate does not have required 'Write' role
         at Microsoft.Kiota.Http.HttpClientLibrary.HttpClientRequestAdapter.ThrowIfFailedResponse...

in case the OpenAPI document provides a description per status code.
The current behavior requires an extension for pretty error messages.

Before putting some tools to work to implement this for other languages, first I'd like to check whether this feature design fits the project.

It adds a constructor with a message to error classes and adds the description from the document to the error map:

            var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
            {
                { "400", (parseNode) => global::ApiSdk.Models.ValidationProblemDetails.CreateFromDiscriminatorValueWithMessage(parseNode, "400 Invalid hash format or hash mismatch") },
                { "401", (parseNode) => global::ApiSdk.Models.ProblemDetails.CreateFromDiscriminatorValueWithMessage(parseNode, "401 Missing or invalid client certificate") },
                { "403", (parseNode) => global::ApiSdk.Models.ProblemDetails.CreateFromDiscriminatorValueWithMessage(parseNode, "403 Client certificate does not have required 'Write' role") },
                { "409", (parseNode) => global::ApiSdk.Models.ProblemDetails.CreateFromDiscriminatorValueWithMessage(parseNode, "409 Upload for this hash already in progress, please retry") },
            };

The existing extension message logic is still intact, so this is used as fallback only.

@koen-lee koen-lee requested a review from a team as a code owner September 25, 2025 12:07
Copy link
Member

@baywet baywet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution!

Comment on lines 351 to 352
errorMappings.TryAdd(errorCode, type);
if (!string.IsNullOrEmpty(description))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the try add result be used in the condition here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, it is quite a corner case where consumer expectations are hard to guess - for this to matter, you'd need duplicate error code mappings where one has a description and the other hasn't.
But you have seen more OpenAPI specs than I so if you say this actually happens and the current behavior is unexpected, then the answer is yes :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I didn't notice but we're duplicating a lot of code with the existing method.
Please:

  • add the description parameter as an optional parameter to the existing method
  • move the condition to the existing method
  • update the condition to consider the try add, so we don't end up in a weird state where we have a description for an error type that doesn't exist
  • remove this new method
  • Update the GetErrorDescriptionMethod to always check whether a matching mapping is present before returning anything (same principle, safety first)

koen-lee and others added 2 commits October 2, 2025 11:46
static lambdas, simplification.

Co-authored-by: Vincent Biret <vincentbiret@hotmail.com>
@koen-lee
Copy link
Author

koen-lee commented Oct 2, 2025

@baywet thanks for the review; I think all your points have been addressed.
We could also add a CodeMethodKind ConstructorWithMessage but I see little value in that.

Is it OK to proceed with other languages in the same manner or is there still room for improvement?

// 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)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should test on the new kind that was introduced (multiple instances)

}
// For error classes with message constructor, pass the message to base constructor
else if (isConstructor && parentClass.IsErrorDefinition &&
currentMethod.Parameters.Any(p => p.IsOfKind(CodeParameterKind.ErrorMessage)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
currentMethod.Parameters.Any(p => p.IsOfKind(CodeParameterKind.ErrorMessage)))
currentMethod.Parameters.Any(static p => p.IsOfKind(CodeParameterKind.ErrorMessage)))

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's probably a static analyser trick I'm missing here that would warn contributors about lambdas that can be static?

WriteFactoryMethodBodyForIntersectionModel(codeElement, parentClass, parseNodeParameter, writer);
else if (codeElement.IsOfKind(CodeMethodKind.FactoryWithErrorMessage))
{
var messageParam = codeElement.Parameters.FirstOrDefault(p => p.IsOfKind(CodeParameterKind.ErrorMessage)) ?? throw new InvalidOperationException($"FactoryWithErrorMessage should have a message parameter");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var messageParam = codeElement.Parameters.FirstOrDefault(p => p.IsOfKind(CodeParameterKind.ErrorMessage)) ?? throw new InvalidOperationException($"FactoryWithErrorMessage should have a message parameter");
var messageParam = codeElement.Parameters.FirstOrDefault(static p => p.IsOfKind(CodeParameterKind.ErrorMessage)) ?? throw new InvalidOperationException($"FactoryWithErrorMessage should have a message parameter");

Comment on lines 351 to 352
errorMappings.TryAdd(errorCode, type);
if (!string.IsNullOrEmpty(description))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I didn't notice but we're duplicating a lot of code with the existing method.
Please:

  • add the description parameter as an optional parameter to the existing method
  • move the condition to the existing method
  • update the condition to consider the try add, so we don't end up in a weird state where we have a description for an error type that doesn't exist
  • remove this new method
  • Update the GetErrorDescriptionMethod to always check whether a matching mapping is present before returning anything (same principle, safety first)

}

// Add message constructor if not already present
if (!codeClass.Methods.Any(static x => x.IsOfKind(CodeMethodKind.Constructor) && x.Parameters.Any(static p => "string".Equals(p.Type.Name, StringComparison.OrdinalIgnoreCase))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should filter on the new kind instead of the name

if (errorMapping.Value.AllTypes.FirstOrDefault()?.TypeDefinition is CodeClass { IsErrorDefinition: true } errorClass)
{
var errorDescription = codeElement.GetErrorDescription(errorMapping.Key);
var statusCodeAndDescription = !string.IsNullOrEmpty(errorDescription)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@baywet I'm having second thoughts on this - I think we shouldn't include the status code key here because it may be confusing in the 4XX/5XX case.
So, just the description when provided and the old behavior when not.
The actual specific response status code has value though; #6951 would help to provide that without conflicting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think this would be confusing for the 4XX/5XX case?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 5XX is not part of the API designer provided error message and the actual response code provides more detailed info. I don't see added value in an ApiException that says "400 4XX Your mistake" over "400 Your mistake".

to avoid confusion with 4xx 5xx  generic codes
commit c3bc041
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Sun Dec 14 15:53:41 2025 +0100

    Fix python and php

commit 0bd60a0
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Sun Dec 14 10:53:47 2025 +0100

    fix php

commit 52d3a94
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Sun Dec 14 10:10:12 2025 +0100

    base CreateConstructor messes up the naming

commit 8dac31f
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Sat Dec 13 12:14:15 2025 +0100

    debugging the generated code

commit 6138205
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Sat Dec 13 11:01:29 2025 +0100

    The Go writer has the last word on constructor names

commit de7416f
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Sat Dec 13 10:20:07 2025 +0100

    update tests to reflect the new proper type enums

commit 87bd2b6
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Sat Dec 13 09:17:39 2025 +0100

    pass the parameter directly

commit 271b4b0
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 21:47:53 2025 +0100

    refactor very similar factory creation

commit 67dc075
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 21:24:32 2025 +0100

    remove switch/if antipattern

commit e9d5bc9
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 20:36:44 2025 +0100

    Simplify param creation

commit 4783f30
Merge: 988bce9 5a492c0
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 20:08:49 2025 +0100

    Merge remote-tracking branch 'upstream/main' into OpenAPI-description-in-exceptions-other-languages

commit 988bce9
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 20:06:51 2025 +0100

    Inline factory method generation

    to align with other languages

commit 56c37ae
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 19:58:13 2025 +0100

    fix other tests

commit 4eb5959
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 15:30:55 2025 +0100

    fix go

commit 12f4639
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 15:16:17 2025 +0100

    update tests

commit 7a5b295
Merge: 9ffe8c4 206e170
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 08:27:18 2025 +0100

    Merge remote-tracking branch 'upstream/main' into OpenAPI-description-in-exceptions-other-languages

commit 9ffe8c4
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 08:01:25 2025 +0100

    restore merge artifact

commit 7a61a84
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Dec 12 07:50:51 2025 +0100

    extract error message parameter creation

commit da6b4ed
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Dec 11 20:38:05 2025 +0100

    Add Ruby

commit 38bf2ee
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Dec 11 20:32:23 2025 +0100

    cleanup Python

commit 4485b78
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Dec 11 20:24:34 2025 +0100

    cleanup PHP

commit 877ad2b
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Dec 11 20:04:47 2025 +0100

    Cleanup Go

commit e39a932
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Dec 11 19:31:12 2025 +0100

    Cleanup Typescript

commit fc11b7f
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Dec 11 19:26:13 2025 +0100

    Cleanup Java

commit 133a78d
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Sep 25 14:03:54 2025 +0200

    feat: add OpenAPI error description enhancements for Python

    - Add parameterless and message constructors to Python error classes
    - Add create_from_discriminator_value_with_message factory method
    - Enhance error mappings to include human-readable descriptions
    - Support constructor inheritance with super().__init__(message)
    - Add comprehensive unit tests for refiner and method writer
    - Maintain backward compatibility with existing error mappings

    🤖 Generated with [Claude Code](https://claude.ai/code)

    Co-Authored-By: Claude <noreply@anthropic.com>

commit f3cc7be
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Sep 26 13:46:05 2025 +0200

    Implement TypeScript error description enhancements

    - Add constructors for error classes with optional message parameter
    - Add createFromDiscriminatorValueWithMessage factory methods for error classes
    - Enhance error mappings in CodeConstantWriter with human-readable descriptions
    - Add comprehensive tests for refiner and writer enhancements
    - Fix test expectations for non-error class factory method behavior
    - Correct call order for AddConstructorsForErrorClasses in TypeScript refiner pipeline

    🤖 Generated with [Claude Code](https://claude.ai/code)

    Co-Authored-By: Claude <noreply@anthropic.com>

commit ae746e5
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Sep 26 10:21:05 2025 +0200

    Implement OpenAPI error description enhancements for PHP

    - Add constructors for error classes (__construct with parameterless and message variants)
    - Add createFromDiscriminatorValueWithMessage factory method for enhanced error handling
    - Enhance error mapping generation with human-readable descriptions using PHP function syntax
    - Add special handling for error factory methods in method writer
    - Add comprehensive tests for PHP error enhancements
    - Follow PHP conventions with camelCase method names and constructor patterns

    🤖 Generated with [Claude Code](https://claude.ai/code)

    Co-Authored-By: Claude <noreply@anthropic.com>

commit eba3aa3
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Fri Sep 26 10:00:24 2025 +0200

    Implement OpenAPI error description enhancements for Go

    - Add factory methods for error classes (NewErrorClass, NewErrorClassWithMessage, CreateFromDiscriminatorValueWithMessage)
    - Enhance error mapping generation with human-readable descriptions using Go function syntax
    - Add special handling for error factory methods in method writer
    - Add comprehensive tests for Go error enhancements
    - Follow Go conventions with factory functions and pointer returns

    🤖 Generated with [Claude Code](https://claude.ai/code)

    Co-Authored-By: Claude <noreply@anthropic.com>

commit 98728fd
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Sep 25 13:36:38 2025 +0200

    Add Dart

commit 24ffc6e
Author: Koen van Leeuwen <koen@logiqs.nl>
Date:   Thu Sep 25 13:24:41 2025 +0200

    Add Java
@koen-lee koen-lee marked this pull request as draft December 14, 2025 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants