Take exception message from OpenAPI document
- Dominant language
- C#
- Stars
- 3.8k
- Forks
- 333
- Avg merge
- 16h 29m
- Merged PRs (30d)
- 116
Description
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:
```c#
var exception = (await action.Should().ThrowExactlyAsync()).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:
```c#
var exception = (await action.Should().ThrowExactlyAsync>()).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:
```json
"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):
```c#
// 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> 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> Headers { get; } = headers;
}
public sealed class ApiException(
string message, int statusCode, string? response, IReadOnlyDictionary> 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).
Contributor guide
Research direction
Start by tracing how generated exceptions handle non-successful responses and how response descriptions from the OpenAPI document are passed into them. Use the 400, 409, and 422 response examples and the shown assertions as the behavioral reference. Done means the generated exception receives the status-specific OpenAPI description as its message while preserving the existing response data and status code.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100