1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-08-31 12:42:00 +00:00

Added support for parsing REST response even though status indicates error

This commit is contained in:
Jkorf 2025-08-25 09:58:03 +02:00
parent d0284c62c0
commit d42de1fe90
3 changed files with 21 additions and 8 deletions

View File

@ -239,7 +239,7 @@ namespace CryptoExchange.Net.Clients
additionalHeaders);
_logger.RestApiSendRequest(request.RequestId, definition, request.Content, string.IsNullOrEmpty(request.Uri.Query) ? "-" : request.Uri.Query, string.Join(", ", request.GetHeaders().Select(h => h.Key + $"=[{string.Join(",", h.Value)}]")));
TotalRequestsMade++;
var result = await GetResponseAsync<T>(request, definition.RateLimitGate, cancellationToken).ConfigureAwait(false);
var result = await GetResponseAsync<T>(definition, request, definition.RateLimitGate, cancellationToken).ConfigureAwait(false);
if (result.Error is not CancellationRequestedError)
{
var originalData = OutputOriginalData ? result.OriginalData : "[Data only available when OutputOriginal = true]";
@ -424,11 +424,13 @@ namespace CryptoExchange.Net.Clients
/// <summary>
/// Executes the request and returns the result deserialized into the type parameter class
/// </summary>
/// <param name="requestDefinition">The request definition</param>
/// <param name="request">The request object to execute</param>
/// <param name="gate">The ratelimit gate used</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns></returns>
protected virtual async Task<WebCallResult<T>> GetResponseAsync<T>(
RequestDefinition requestDefinition,
IRequest request,
IRateLimitGate? gate,
CancellationToken cancellationToken)
@ -448,7 +450,7 @@ namespace CryptoExchange.Net.Clients
var outputOriginalData = ApiOptions.OutputOriginalData ?? ClientOptions.OutputOriginalData;
accessor = CreateAccessor();
if (!response.IsSuccessStatusCode)
if (!response.IsSuccessStatusCode && !requestDefinition.TryParseOnNonSuccess)
{
// Error response
var readResult = await accessor.Read(responseStream, true).ConfigureAwait(false);
@ -488,7 +490,7 @@ namespace CryptoExchange.Net.Clients
}
// Json response received
var parsedError = TryParseError(response.ResponseHeaders, accessor);
var parsedError = TryParseError(requestDefinition, response.ResponseHeaders, accessor);
if (parsedError != null)
{
if (parsedError is ServerRateLimitError rateError)
@ -541,10 +543,11 @@ namespace CryptoExchange.Net.Clients
/// This method will be called for each response to be able to check if the response is an error or not.
/// If the response is an error this method should return the parsed error, else it should return null
/// </summary>
/// <param name="requestDefinition">Request definition</param>
/// <param name="accessor">Data accessor</param>
/// <param name="responseHeaders">The response headers</param>
/// <returns>Null if not an error, Error otherwise</returns>
protected virtual Error? TryParseError(KeyValuePair<string, string[]>[] responseHeaders, IMessageAccessor accessor) => null;
protected virtual Error? TryParseError(RequestDefinition requestDefinition, KeyValuePair<string, string[]>[] responseHeaders, IMessageAccessor accessor) => null;
/// <summary>
/// Can be used to indicate that a request should be retried. Defaults to false. Make sure to retry a max number of times (based on the the tries parameter) or the request will retry forever.

View File

@ -62,6 +62,11 @@ namespace CryptoExchange.Net.Objects
/// </summary>
public bool PreventCaching { get; set; }
/// <summary>
/// Whether the response to this requests should attempted to be parsed even when the status indicates failure
/// </summary>
public bool TryParseOnNonSuccess { get; set; }
/// <summary>
/// Connection id
/// </summary>

View File

@ -46,6 +46,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="parameterPosition">Parameter position</param>
/// <param name="arraySerialization">Array serialization type</param>
/// <param name="preventCaching">Prevent request caching</param>
/// <param name="tryParseOnNonSuccess">Try parse the response even when status is not success</param>
/// <returns></returns>
public RequestDefinition GetOrCreate(
HttpMethod method,
@ -57,8 +58,9 @@ namespace CryptoExchange.Net.Objects
RequestBodyFormat? requestBodyFormat = null,
HttpMethodParameterPosition? parameterPosition = null,
ArrayParametersSerialization? arraySerialization = null,
bool? preventCaching = null)
=> GetOrCreate(method + path, method, path, rateLimitGate, weight, authenticated, limitGuard, requestBodyFormat, parameterPosition, arraySerialization, preventCaching);
bool? preventCaching = null,
bool? tryParseOnNonSuccess = null)
=> GetOrCreate(method + path, method, path, rateLimitGate, weight, authenticated, limitGuard, requestBodyFormat, parameterPosition, arraySerialization, preventCaching, tryParseOnNonSuccess);
/// <summary>
/// Get a definition if it is already in the cache or create a new definition and add it to the cache
@ -74,6 +76,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="parameterPosition">Parameter position</param>
/// <param name="arraySerialization">Array serialization type</param>
/// <param name="preventCaching">Prevent request caching</param>
/// <param name="tryParseOnNonSuccess">Try parse the response even when status is not success</param>
/// <returns></returns>
public RequestDefinition GetOrCreate(
string identifier,
@ -86,7 +89,8 @@ namespace CryptoExchange.Net.Objects
RequestBodyFormat? requestBodyFormat = null,
HttpMethodParameterPosition? parameterPosition = null,
ArrayParametersSerialization? arraySerialization = null,
bool? preventCaching = null)
bool? preventCaching = null,
bool? tryParseOnNonSuccess = null)
{
if (!_definitions.TryGetValue(identifier, out var def))
@ -100,7 +104,8 @@ namespace CryptoExchange.Net.Objects
ArraySerialization = arraySerialization,
RequestBodyFormat = requestBodyFormat,
ParameterPosition = parameterPosition,
PreventCaching = preventCaching ?? false
PreventCaching = preventCaching ?? false,
TryParseOnNonSuccess = tryParseOnNonSuccess ?? false
};
_definitions.TryAdd(identifier, def);
}