Refactor HTTP response handling and add JSON support
Enhanced `HandleResponseAsync` to return response body as a string and log successful responses. Introduced `JsonOptions` for consistent JSON serialization/deserialization. Added a generic `Deserialize<T>` method for deserializing JSON responses. Updated method signatures to support nullable reference types.
This commit is contained in:
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -73,18 +74,22 @@ namespace ReC.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logs the outcome of an HTTP response. Throws a <see cref="ReCApiException"/> when the
|
/// JSON serializer options used when deserializing API responses.
|
||||||
/// response indicates a non-success status code; otherwise (optionally) writes an informational
|
/// </summary>
|
||||||
/// log entry containing the request and response details.
|
public static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the response body and logs the outcome. Throws a <see cref="ReCApiException"/> when
|
||||||
|
/// the response indicates a non-success status code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="response">The HTTP response to inspect.</param>
|
|
||||||
/// <param name="logger">An optional logger used to record the outcome. May be <see langword="null"/>.</param>
|
|
||||||
/// <param name="logSuccess">When <see langword="false"/>, successful responses are not logged.</param>
|
|
||||||
/// <param name="cancel">A token to cancel the operation.</param>
|
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
public static async Task HandleResponseAsync(HttpResponseMessage response, ILogger logger = null, bool logSuccess = true, CancellationToken cancel = default)
|
public static async Task<string> HandleResponseAsync(HttpResponseMessage response, ILogger logger = null, bool logSuccess = true, CancellationToken cancel = default)
|
||||||
#else
|
#else
|
||||||
public static async Task HandleResponseAsync(HttpResponseMessage response, ILogger? logger = null, bool logSuccess = true, CancellationToken cancel = default)
|
public static async Task<string?> HandleResponseAsync(HttpResponseMessage response, ILogger? logger = null, bool logSuccess = true, CancellationToken cancel = default)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
var request = response.RequestMessage;
|
var request = response.RequestMessage;
|
||||||
@@ -92,20 +97,6 @@ namespace ReC.Client
|
|||||||
var uri = request?.RequestUri;
|
var uri = request?.RequestUri;
|
||||||
var statusCode = (int)response.StatusCode;
|
var statusCode = (int)response.StatusCode;
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
if (logSuccess)
|
|
||||||
{
|
|
||||||
logger?.LogInformation(
|
|
||||||
"ReC API request succeeded. {Method} {Uri} -> {StatusCode} ({ReasonPhrase})",
|
|
||||||
method,
|
|
||||||
uri,
|
|
||||||
statusCode,
|
|
||||||
response.ReasonPhrase);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
string body = null;
|
string body = null;
|
||||||
#else
|
#else
|
||||||
@@ -123,15 +114,44 @@ namespace ReC.Client
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// Swallow body read failures; status info is still propagated.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
if (logSuccess)
|
||||||
|
{
|
||||||
|
logger?.LogInformation(
|
||||||
|
"ReC API request succeeded. {Method} {Uri} -> {StatusCode} ({ReasonPhrase})",
|
||||||
|
method,
|
||||||
|
uri,
|
||||||
|
statusCode,
|
||||||
|
response.ReasonPhrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
var message = $"ReC API request failed with status {statusCode} ({response.ReasonPhrase}). "
|
var message = $"ReC API request failed with status {statusCode} ({response.ReasonPhrase}). "
|
||||||
+ $"{method} {uri}"
|
+ $"{method} {uri}"
|
||||||
+ (string.IsNullOrWhiteSpace(body) ? string.Empty : $": {body}");
|
+ (string.IsNullOrWhiteSpace(body) ? string.Empty : $": {body}");
|
||||||
|
|
||||||
throw new ReCApiException(message, response.StatusCode, response.ReasonPhrase, body, method, uri);
|
throw new ReCApiException(message, response.StatusCode, response.ReasonPhrase, body, method, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserializes a JSON body string into <typeparamref name="T"/>.
|
||||||
|
/// </summary>
|
||||||
|
#if NETFRAMEWORK
|
||||||
|
public static T Deserialize<T>(string body)
|
||||||
|
#else
|
||||||
|
public static T? Deserialize<T>(string? body)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(body))
|
||||||
|
return default;
|
||||||
|
|
||||||
|
return JsonSerializer.Deserialize<T>(body, JsonOptions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user