Skip to content

Commit

Permalink
Merge pull request #108 from VincentVrijburg/feature/http-improvements
Browse files Browse the repository at this point in the history
Improve error message deserialization on value types other than string
  • Loading branch information
VincentVrijburg authored Jul 6, 2024
2 parents b04b1b8 + 7c004d7 commit 8ce3d8f
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 7 deletions.
24 changes: 24 additions & 0 deletions src/Moneybird.Net/Extensions/JsonElementExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Linq;
using System.Text.Json;

namespace Moneybird.Net.Extensions
{
internal static class JsonElementExtensions
{
/// <summary>
/// Get the error message from the error JsonElement.
/// </summary>
/// <param name="jsonElement">The JsonElement from the error response content.</param>
/// <returns>The error message as a string.</returns>
public static string GetErrorMessage(this JsonElement jsonElement) {
var error = jsonElement.GetProperty("error");
var message = error.ValueKind switch
{
JsonValueKind.Object => string.Join(", ", error.EnumerateObject().SelectMany(prop => prop.Value.EnumerateArray().Select(val => $"{prop.Name}: {val.GetString()}")).ToList()),
_ => error.GetString(),
};

return message;
}
}
}
17 changes: 10 additions & 7 deletions src/Moneybird.Net/Http/RequesterBase.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
using Moneybird.Net.Extensions;

namespace Moneybird.Net.Http
{
[ExcludeFromCodeCoverage]
public abstract class RequesterBase : IDisposable
{
private readonly HttpClient _httpClient;
Expand Down Expand Up @@ -51,15 +54,15 @@ protected HttpRequestMessage ConstructRequest(string host, string relativeUrl, s

return requestMessage;
}
protected string GetQueryString(List<string> queryParameters)

private string GetQueryString(List<string> queryParameters)
{
return queryParameters
.Where(param => !string.IsNullOrWhiteSpace(param))
.Aggregate(string.Empty, (current, param) => current + ("&" + param));
.Aggregate(string.Empty, (current, param) => current + "&" + param);
}
protected void HandleRequestFailure(HttpResponseMessage response)

private void HandleRequestFailure(HttpResponseMessage response)
{
try
{
Expand All @@ -70,8 +73,8 @@ protected void HandleRequestFailure(HttpResponseMessage response)
try
{
var json = response.Content.ReadAsStringAsync().Result;
var obj = JsonDocument.Parse(json);
message = obj.RootElement[0].GetProperty("error").GetString();
var jsonDocument = JsonDocument.Parse(json);
message = jsonDocument.RootElement.GetErrorMessage();
}
catch {
message = response.StatusCode.ToString();
Expand Down
48 changes: 48 additions & 0 deletions tests/Moneybird.Net.Tests/Extensions/JsonElementExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Text.Json;
using Moneybird.Net.Extensions;
using Xunit;

namespace Moneybird.Net.Tests.Extensions;

public class JsonElementExtensionsTests
{
[Fact]
public void GetErrorMessage_FromStringErrorJsonElement_Returns_CorrectString()
{
const string json = "{\"error\":\"Contact is required\",\"symbolic\":{\"contact\":\"required\"}}";
var jsonElement = JsonDocument.Parse(json);
var actualValue = jsonElement.RootElement.GetErrorMessage();

Assert.Equal("Contact is required", actualValue);
}

[Fact]
public void GetErrorMessage_FromObjectErrorJsonElement_Returns_CorrectString()
{
const string json = "{\"error\":{\"delivery_method\":[\"The sender address must contain an email address\"]}}";
var jsonElement = JsonDocument.Parse(json);
var actualValue = jsonElement.RootElement.GetErrorMessage();

Assert.Equal("delivery_method: The sender address must contain an email address", actualValue);
}

[Fact]
public void GetErrorMessage_FromObjectsErrorJsonElement_Returns_CorrectString()
{
const string json = "{\"error\":{\"firstname\":[\"is required\"],\"lastname\":[\"is required\"],\"company_name\":[\"is required\"]}}";
var jsonElement = JsonDocument.Parse(json);
var actualValue = jsonElement.RootElement.GetErrorMessage();

Assert.Equal("firstname: is required, lastname: is required, company_name: is required", actualValue);
}

[Fact]
public void GetErrorMessage_FromObjectMultipleErrorsJsonElement_Returns_CorrectString()
{
const string json = "{\"error\":{\"delivery_method\":[\"The delivery method is required\",\"The sender address must contain an email address\"]}}";
var jsonElement = JsonDocument.Parse(json);
var actualValue = jsonElement.RootElement.GetErrorMessage();

Assert.Equal("delivery_method: The delivery method is required, delivery_method: The sender address must contain an email address", actualValue);
}
}

0 comments on commit 8ce3d8f

Please sign in to comment.