fix: Parse error messages from service with title & errors list

spectre-console-remove-di-hacks
Robert Dailey 8 months ago
parent 0afe1ee005
commit 4f5946bc67

@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Text.Json;
using JetBrains.Annotations;
using Recyclarr.Json;
namespace Recyclarr.Cli.Processors.ErrorHandling;
@ -64,4 +65,34 @@ public sealed class ErrorResponseParser
return false;
}
}
[UsedImplicitly(ImplicitUseKindFlags.Assign)]
private sealed record ServiceErrorsList(string Title, Dictionary<string, List<string>> Errors);
[SuppressMessage("Design", "CA1031:Do not catch general exception types")]
public bool DeserializeServiceErrorList()
{
try
{
using var stream = _streamFactory();
var value = JsonSerializer.Deserialize<ServiceErrorsList>(stream, _jsonSettings);
if (value is null)
{
return false;
}
_log.Error("Error message from remote service: {Message:l}", value.Title);
foreach (var (topic, msg) in value.Errors.SelectMany(x => x.Value.Select(y => (x.Key, Msg: y))))
{
_log.Error("{Topic:l}: {Message:l}", topic, msg);
}
return true;
}
catch
{
return false;
}
}
}

@ -33,6 +33,7 @@ public class FlurlHttpExceptionHandler : IFlurlHttpExceptionHandler
{
var parser = new ErrorResponseParser(_log, responseBody);
// Try to parse validation errors
if (parser.DeserializeList(s => s
.Select(x => x.GetProperty("errorMessage").GetString())
.NotNull(x => !string.IsNullOrEmpty(x))))
@ -40,11 +41,18 @@ public class FlurlHttpExceptionHandler : IFlurlHttpExceptionHandler
return;
}
// Try to parse single error message
if (parser.Deserialize(s => s.GetProperty("message").GetString()))
{
return;
}
// A list of errors with a title
if (parser.DeserializeServiceErrorList())
{
return;
}
// Last resort
_log.Error("Reason: Unable to determine. Please report this as a bug and attach your `verbose.log` file.");
}

@ -0,0 +1,11 @@
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-e2ebf7693f107cf617432d815b429382-d07ea6c6fd009421-00",
"errors": {
"$.items[0].id": [
"The JSON value could not be converted to System.Int32. Path: $.items[0].id | LineNumber: 0 | BytePositionInLine: 3789."
]
}
}

@ -56,4 +56,28 @@ public class FlurlHttpExceptionHandlerTest
logs.Should().HaveCount(expectedSubstrings.Length);
logs.Zip(expectedSubstrings).Should().OnlyContain(pair => pair.First.Contains(pair.Second));
}
[Test, AutoMockData]
public async Task Http_exception_print_title_and_errors_list(
[Frozen(Matching.ImplementedInterfaces)] TestableLogger log,
IServiceErrorMessageExtractor extractor,
FlurlHttpExceptionHandler sut)
{
var resourceReader = new ResourceDataReader(typeof(FlurlHttpExceptionHandlerTest), "Data");
var responseContent = resourceReader.ReadData("title_errors_list.json");
extractor.GetErrorMessage().Returns(responseContent);
await sut.ProcessServiceErrorMessages(extractor);
var logs = log.Messages.ToList();
var expectedSubstrings = new[]
{
"One or more validation errors occurred",
"$.items[0].id: The JSON value could not be converted to System.Int32. Path: $.items[0].id | LineNumber: 0 | BytePositionInLine: 3789."
};
logs.Should().HaveCount(expectedSubstrings.Length);
logs.Zip(expectedSubstrings).Should().OnlyContain(pair => pair.First.Contains(pair.Second));
}
}

Loading…
Cancel
Save