Skip to content

Take exception message from OpenAPI document #4349

@bkoelman

Description

@bkoelman

Today, when a non-successful status code is returned (which is described in the OpenAPI document), an exception is thrown with an unhelpful generic message:

Exception of type 'MyProject.Models.ErrorResponseDocument' was thrown.

In contrast, NSwag takes the message from the OpenAPI document.

For comparison, here are my test assertions from Kiota:

var exception = (await action.Should().ThrowExactlyAsync<ErrorResponseDocument>()).Which;
exception.ResponseStatusCode.Should().Be((int)HttpStatusCode.Conflict);
exception.Message.Should().Be($"Exception of type '{typeof(ErrorResponseDocument).FullName}' was thrown.");
exception.Errors.ShouldHaveCount(1);

Compared with those from NSwag:

var exception = (await action.Should().ThrowExactlyAsync<ApiException<ErrorResponseDocument>>()).Which;
exception.StatusCode.Should().Be((int)HttpStatusCode.Conflict);
exception.Message.Should().Be("HTTP 409: The request body contains conflicting information or another resource with the same ID already exists.");
exception.Result.Errors.ShouldHaveCount(1);

Here's the OpenAPI fragment the code was generated against:

"responses": {
  "400": {
    "description": "The query string is invalid or the request body is missing or malformed.",
    "content": {
      "application/vnd.api+json": {
        "schema": {
          "$ref": "#/components/schemas/errorResponseDocument"
        }
      }
    }
  },
  "409": {
    "description": "The request body contains conflicting information or another resource with the same ID already exists.",
    "content": {
      "application/vnd.api+json": {
        "schema": {
          "$ref": "#/components/schemas/errorResponseDocument"
        }
      }
    }
  },
  "422": {
    "description": "Validation of the request body failed.",
    "content": {
      "application/vnd.api+json": {
        "schema": {
          "$ref": "#/components/schemas/errorResponseDocument"
        }
      }
    }
  }
}

And, for reference, our shared ApiException class we point NSwag to, where we format the exception message by prefixing it with the HTTP status code (note: the constructor signatures are prescribed by NSwag):

// We cannot rely on generating ApiException as soon as we are generating multiple clients, see https://github.com/RicoSuter/NSwag/issues/2839#issuecomment-776647377.
// Instead, we configure NSwag to point to the exception below in the generated code.

namespace JsonApiDotNetCore.OpenApi.Client.NSwag;

public class ApiException(string message, int statusCode, string? response, IReadOnlyDictionary<string, IEnumerable<string>> headers, Exception? innerException)
    : Exception($"HTTP {statusCode}: {message}", innerException)
{
    public int StatusCode { get; } = statusCode;
    public virtual string? Response { get; } = string.IsNullOrEmpty(response) ? null : response;
    public IReadOnlyDictionary<string, IEnumerable<string>> Headers { get; } = headers;
}

public sealed class ApiException<TResult>(
    string message, int statusCode, string? response, IReadOnlyDictionary<string, IEnumerable<string>> headers, TResult result, Exception? innerException)
    : ApiException(message, statusCode, response, headers, innerException)
{
    public TResult Result { get; } = result;
    public override string Response => $"The response body is unavailable. Use the {nameof(Result)} property instead.";
}

So, to summarize, would it be possible for Kiota to use the text from the OpenAPI document as the Exception.Message value of the generated exception class? It should be a parameter (like in NSwag), because the same exception type could be used for multiple status codes (each with a different message).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgeneratorIssues or improvements relater to generation capabilities.help wantedIssue caused by core project dependency modules or library

    Type

    No type

    Projects

    Status

    New📃

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions