From 94232057aa700d8ad93e0758d880ef51905036bd Mon Sep 17 00:00:00 2001 From: RobinTTY Date: Sun, 18 Aug 2024 13:36:39 +0200 Subject: [PATCH 1/5] Prepare ability to check rate limits (#18) --- docs/release-notes/v10_0_0.md | 4 +- .../Endpoints/AccountsEndpoint.cs | 9 ++- .../Endpoints/InstitutionsEndpoint.cs | 3 +- .../Models/Responses/ApiRateLimits.cs | 60 +++++++++++++++++++ .../Models/Responses/NordigenApiResponse.cs | 34 +++++++++-- .../NordigenClient.cs | 9 +-- .../release-notes.txt | 2 +- 7 files changed, 105 insertions(+), 16 deletions(-) create mode 100644 src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs diff --git a/docs/release-notes/v10_0_0.md b/docs/release-notes/v10_0_0.md index 83a0167..cea4c17 100644 --- a/docs/release-notes/v10_0_0.md +++ b/docs/release-notes/v10_0_0.md @@ -39,8 +39,8 @@ public async Task, BasicResponse>> GetInst The `TokenPairUpdated` event is now raised whenever the `JsonWebTokenPair` property is successfully updated. Not only when it was automatically updated but also when done so by the user. -**Full Changelog**: [v9.0.0...v10.0.0](https://github.com/RobinTTY/NordigenApiClient/compare/v9.0.0...v10.0.0) - ## Other improvements A full documentation of the library is now available at: [https://robintty.github.io/NordigenApiClient/](https://robintty.github.io/NordigenApiClient/) + +**Full Changelog**: [v9.0.0...v10.0.0](https://github.com/RobinTTY/NordigenApiClient/compare/v9.0.0...v10.0.0) diff --git a/src/RobinTTY.NordigenApiClient/Endpoints/AccountsEndpoint.cs b/src/RobinTTY.NordigenApiClient/Endpoints/AccountsEndpoint.cs index 4113822..82e6ec0 100644 --- a/src/RobinTTY.NordigenApiClient/Endpoints/AccountsEndpoint.cs +++ b/src/RobinTTY.NordigenApiClient/Endpoints/AccountsEndpoint.cs @@ -46,8 +46,9 @@ private async Task, AccountsError>> GetBalance { var response = await _nordigenClient.MakeRequest( $"{NordigenEndpointUrls.AccountsEndpoint}{accountId}/balances/", HttpMethod.Get, cancellationToken); + return new NordigenApiResponse, AccountsError>(response.StatusCode, response.IsSuccess, - response.Result?.Balances, response.Error); + response.Result?.Balances, response.Error, response.RateLimits); } /// @@ -65,8 +66,9 @@ private async Task> GetAc { var response = await _nordigenClient.MakeRequest( $"{NordigenEndpointUrls.AccountsEndpoint}{id}/details/", HttpMethod.Get, cancellationToken); + return new NordigenApiResponse(response.StatusCode, response.IsSuccess, - response.Result?.Account, response.Error); + response.Result?.Account, response.Error, response.RateLimits); } /// @@ -111,8 +113,9 @@ private async Task> GetT var response = await _nordigenClient.MakeRequest( $"{NordigenEndpointUrls.AccountsEndpoint}{id}/transactions/", HttpMethod.Get, cancellationToken, query); + return new NordigenApiResponse(response.StatusCode, response.IsSuccess, - response.Result?.Transactions, response.Error); + response.Result?.Transactions, response.Error, response.RateLimits); } #if NET6_0_OR_GREATER diff --git a/src/RobinTTY.NordigenApiClient/Endpoints/InstitutionsEndpoint.cs b/src/RobinTTY.NordigenApiClient/Endpoints/InstitutionsEndpoint.cs index c2aa573..9d624d0 100644 --- a/src/RobinTTY.NordigenApiClient/Endpoints/InstitutionsEndpoint.cs +++ b/src/RobinTTY.NordigenApiClient/Endpoints/InstitutionsEndpoint.cs @@ -60,8 +60,7 @@ public async Task, BasicResponse>> GetInst NordigenEndpointUrls.InstitutionsEndpoint, HttpMethod.Get, cancellationToken, query); return new NordigenApiResponse, BasicResponse>(response.StatusCode, response.IsSuccess, - response.Result, - response.Error); + response.Result, response.Error, response.RateLimits); } /// diff --git a/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs new file mode 100644 index 0000000..9f7f1b8 --- /dev/null +++ b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs @@ -0,0 +1,60 @@ +using RobinTTY.NordigenApiClient.Endpoints; + +namespace RobinTTY.NordigenApiClient.Models.Responses; + +/// +/// The rate limits of the GoCardless API. +/// +public class ApiRateLimits +{ + /// + /// Indicates the maximum number of allowed requests within the defined time window. + /// + public int RequestLimit { get; set; } + /// + /// Indicates the number of remaining requests you can make in the current time window. + /// + public int RemainingRequests { get; set; } + /// + /// Indicates the time remaining in the current time window (in seconds). + /// + public int RemainingSecondsInTimeWindow { get; set; } + /// + /// Indicates the maximum number of allowed requests to the + /// within the defined time window. + /// + public int MaxAccountRequests { get; set; } + /// + /// Indicates the number of remaining requests to the + /// you can make in the current time window. + /// + public int RemainingAccountRequests { get; set; } + /// + /// Indicates the time remaining in the current time window (in seconds) for requests + /// to the . + /// + public int RemainingSecondsInAccountTimeWindow { get; set; } + + /// + /// Creates a new instance of . + /// + /// Indicates the maximum number of allowed requests within the defined time window. + /// Indicates the number of remaining requests you can make in the current time window. + /// Indicates the time remaining in the current time window (in seconds). + /// Indicates the maximum number of allowed requests to the + /// within the defined time window. + /// Indicates the number of remaining requests to the + /// you can make in the current time window. + /// Indicates the time remaining in the current time window (in seconds) for requests + /// to the . + public ApiRateLimits(int requestLimit, int remainingRequests, int remainingTimeInTimeWindow, int maxAccountRequests, + int remainingAccountRequests, int remainingTimeInAccountTimeWindow) + { + RequestLimit = requestLimit; + RemainingRequests = remainingRequests; + RemainingSecondsInTimeWindow = remainingTimeInTimeWindow; + MaxAccountRequests = maxAccountRequests; + RemainingAccountRequests = remainingAccountRequests; + RemainingSecondsInAccountTimeWindow = remainingTimeInAccountTimeWindow; + } +} diff --git a/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs b/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs index 1b23285..abf0ef4 100644 --- a/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs +++ b/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs @@ -34,6 +34,11 @@ public class NordigenApiResponse where TResult : class where TE /// The error returned by the API. Null if the HTTP response was successful. /// public TError? Error { get; } + + /// + /// The rate limits of the GoCardless API. + /// + public ApiRateLimits RateLimits { get; } /// /// Creates a new instance of . @@ -42,12 +47,15 @@ public class NordigenApiResponse where TResult : class where TE /// Indicates whether the HTTP response was successful. /// The result returned by the API. Null if the the HTTP response was not successful. /// The error returned by the API. Null if the HTTP response was successful. - public NordigenApiResponse(HttpStatusCode statusCode, bool isSuccess, TResult? result, TError? apiError) + /// The rate limits of the GoCardless API. + public NordigenApiResponse(HttpStatusCode statusCode, bool isSuccess, TResult? result, + TError? apiError, ApiRateLimits rateLimits) { StatusCode = statusCode; IsSuccess = isSuccess; Result = result; Error = apiError; + RateLimits = rateLimits; } /// @@ -60,25 +68,25 @@ public NordigenApiResponse(HttpStatusCode statusCode, bool isSuccess, TResult? r internal static async Task> FromHttpResponse(HttpResponseMessage response, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) { + var rateLimits = GetRateLimits(response); #if NET6_0_OR_GREATER var responseJson = await response.Content.ReadAsStringAsync(cancellationToken); #else var responseJson = await response.Content.ReadAsStringAsync(); #endif - try { if (response.IsSuccessStatusCode) { var result = await response.Content.ReadFromJsonAsync(options, cancellationToken); return new NordigenApiResponse(response.StatusCode, response.IsSuccessStatusCode, - result, null); + result, null, rateLimits); } else { var result = await response.Content.ReadFromJsonAsync(options, cancellationToken); return new NordigenApiResponse(response.StatusCode, response.IsSuccessStatusCode, - null, result); + null, result, rateLimits); } } catch (JsonException ex) @@ -88,4 +96,22 @@ internal static async Task> FromHttpRespons $"The following JSON content caused the problem: {responseJson}", ex); } } + + private static ApiRateLimits GetRateLimits(HttpResponseMessage response) + { + response.Headers.TryGetValues("HTTP_X_RATELIMIT_LIMIT", out var requestLimitInTimeWindow); + response.Headers.TryGetValues("HTTP_X_RATELIMIT_REMAINING", out var remainingRequestsInTimeWindow); + response.Headers.TryGetValues("HTTP_X_RATELIMIT_RESET", out var remainingTimeInTimeWindow); + response.Headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_LIMIT", out var maxAccountRequestsInTimeWindow); + response.Headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_REMAINING", out var remainingAccountRequestsInTimeWindow); + response.Headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_RESET", out var remainingTimeInAccountTimeWindow); + + return new ApiRateLimits( + requestLimitInTimeWindow != null ? int.Parse(requestLimitInTimeWindow.First()) : 0, + remainingRequestsInTimeWindow != null ? int.Parse(remainingRequestsInTimeWindow.First()) : 0, + remainingTimeInTimeWindow != null ? int.Parse(remainingTimeInTimeWindow.First()) : 0, + maxAccountRequestsInTimeWindow != null ? int.Parse(maxAccountRequestsInTimeWindow.First()) : 0, + remainingAccountRequestsInTimeWindow != null ? int.Parse(remainingAccountRequestsInTimeWindow.First()) : 0, + remainingTimeInAccountTimeWindow != null ? int.Parse(remainingTimeInAccountTimeWindow.First()) : 0); + } } diff --git a/src/RobinTTY.NordigenApiClient/NordigenClient.cs b/src/RobinTTY.NordigenApiClient/NordigenClient.cs index a3ee5a0..305492b 100644 --- a/src/RobinTTY.NordigenApiClient/NordigenClient.cs +++ b/src/RobinTTY.NordigenApiClient/NordigenClient.cs @@ -119,7 +119,8 @@ internal async Task> MakeRequest(tokenResponse.StatusCode, tokenResponse.IsSuccess, - null, new TError {Summary = tokenResponse.Error.Summary, Detail = tokenResponse.Error.Detail}); + null, new TError {Summary = tokenResponse.Error.Summary, Detail = tokenResponse.Error.Detail}, + tokenResponse.RateLimits); } finally { @@ -180,13 +181,13 @@ private async Task> TryGetV ? new JsonWebTokenPair(response.Result.AccessToken, JsonWebTokenPair.RefreshToken, response.Result!.AccessExpires, JsonWebTokenPair.RefreshExpires) : null; - + return new NordigenApiResponse(response.StatusCode, response.IsSuccess, - token, response.Error); + token, response.Error, response.RateLimits); } // Token pair is still valid and can be returned - wrap in NordigenApiResponse return new NordigenApiResponse(HttpStatusCode.OK, true, JsonWebTokenPair, - null); + null, new ApiRateLimits(-1, -1, -1, -1, 0, -1)); } } diff --git a/src/RobinTTY.NordigenApiClient/release-notes.txt b/src/RobinTTY.NordigenApiClient/release-notes.txt index cdc48b7..6711509 100644 --- a/src/RobinTTY.NordigenApiClient/release-notes.txt +++ b/src/RobinTTY.NordigenApiClient/release-notes.txt @@ -1,2 +1,2 @@ This version improves many aspects of the library. Since this version contains breaking changes please check the release notes before updating. -For the full release notes please see: https://github.com/RobinTTY/NordigenApiClient/releases/tag/v9.0.0 \ No newline at end of file +For the full release notes please see: https://github.com/RobinTTY/NordigenApiClient/releases/tag/v10.0.0 \ No newline at end of file From f9c078403424b5f013c77439c74f0063a891cec9 Mon Sep 17 00:00:00 2001 From: RobinTTY Date: Sun, 18 Aug 2024 13:49:04 +0200 Subject: [PATCH 2/5] Move logic reading related headers to ApiRateLimits class --- .../Models/Responses/ApiRateLimits.cs | 24 ++++++++++++++++++- .../Models/Responses/NordigenApiResponse.cs | 23 ++---------------- .../release-notes.txt | 4 ++-- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs index 9f7f1b8..a6609f6 100644 --- a/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs +++ b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs @@ -1,4 +1,5 @@ -using RobinTTY.NordigenApiClient.Endpoints; +using System.Net.Http.Headers; +using RobinTTY.NordigenApiClient.Endpoints; namespace RobinTTY.NordigenApiClient.Models.Responses; @@ -57,4 +58,25 @@ public ApiRateLimits(int requestLimit, int remainingRequests, int remainingTimeI RemainingAccountRequests = remainingAccountRequests; RemainingSecondsInAccountTimeWindow = remainingTimeInAccountTimeWindow; } + + /// + /// Creates a new instance of . + /// + /// The headers of the HTTP response containing the rate limit information. + public ApiRateLimits(HttpResponseHeaders headers) + { + headers.TryGetValues("HTTP_X_RATELIMIT_LIMIT", out var requestLimitInTimeWindow); + headers.TryGetValues("HTTP_X_RATELIMIT_REMAINING", out var remainingRequestsInTimeWindow); + headers.TryGetValues("HTTP_X_RATELIMIT_RESET", out var remainingTimeInTimeWindow); + headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_LIMIT", out var maxAccountRequestsInTimeWindow); + headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_REMAINING", out var remainingAccountRequestsInTimeWindow); + headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_RESET", out var remainingTimeInAccountTimeWindow); + + RequestLimit = requestLimitInTimeWindow != null ? int.Parse(requestLimitInTimeWindow.First()) : 0; + RemainingRequests = remainingRequestsInTimeWindow != null ? int.Parse(remainingRequestsInTimeWindow.First()) : 0; + RemainingSecondsInTimeWindow = remainingTimeInTimeWindow != null ? int.Parse(remainingTimeInTimeWindow.First()) : 0; + MaxAccountRequests = maxAccountRequestsInTimeWindow != null ? int.Parse(maxAccountRequestsInTimeWindow.First()) : 0; + RemainingAccountRequests = remainingAccountRequestsInTimeWindow != null ? int.Parse(remainingAccountRequestsInTimeWindow.First()) : 0; + RemainingSecondsInAccountTimeWindow = remainingTimeInAccountTimeWindow != null ? int.Parse(remainingTimeInAccountTimeWindow.First()) : 0; + } } diff --git a/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs b/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs index abf0ef4..c4dd9ee 100644 --- a/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs +++ b/src/RobinTTY.NordigenApiClient/Models/Responses/NordigenApiResponse.cs @@ -68,7 +68,6 @@ public NordigenApiResponse(HttpStatusCode statusCode, bool isSuccess, TResult? r internal static async Task> FromHttpResponse(HttpResponseMessage response, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) { - var rateLimits = GetRateLimits(response); #if NET6_0_OR_GREATER var responseJson = await response.Content.ReadAsStringAsync(cancellationToken); #else @@ -80,13 +79,13 @@ internal static async Task> FromHttpRespons { var result = await response.Content.ReadFromJsonAsync(options, cancellationToken); return new NordigenApiResponse(response.StatusCode, response.IsSuccessStatusCode, - result, null, rateLimits); + result, null, new ApiRateLimits(response.Headers)); } else { var result = await response.Content.ReadFromJsonAsync(options, cancellationToken); return new NordigenApiResponse(response.StatusCode, response.IsSuccessStatusCode, - null, result, rateLimits); + null, result, new ApiRateLimits(response.Headers)); } } catch (JsonException ex) @@ -96,22 +95,4 @@ internal static async Task> FromHttpRespons $"The following JSON content caused the problem: {responseJson}", ex); } } - - private static ApiRateLimits GetRateLimits(HttpResponseMessage response) - { - response.Headers.TryGetValues("HTTP_X_RATELIMIT_LIMIT", out var requestLimitInTimeWindow); - response.Headers.TryGetValues("HTTP_X_RATELIMIT_REMAINING", out var remainingRequestsInTimeWindow); - response.Headers.TryGetValues("HTTP_X_RATELIMIT_RESET", out var remainingTimeInTimeWindow); - response.Headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_LIMIT", out var maxAccountRequestsInTimeWindow); - response.Headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_REMAINING", out var remainingAccountRequestsInTimeWindow); - response.Headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_RESET", out var remainingTimeInAccountTimeWindow); - - return new ApiRateLimits( - requestLimitInTimeWindow != null ? int.Parse(requestLimitInTimeWindow.First()) : 0, - remainingRequestsInTimeWindow != null ? int.Parse(remainingRequestsInTimeWindow.First()) : 0, - remainingTimeInTimeWindow != null ? int.Parse(remainingTimeInTimeWindow.First()) : 0, - maxAccountRequestsInTimeWindow != null ? int.Parse(maxAccountRequestsInTimeWindow.First()) : 0, - remainingAccountRequestsInTimeWindow != null ? int.Parse(remainingAccountRequestsInTimeWindow.First()) : 0, - remainingTimeInAccountTimeWindow != null ? int.Parse(remainingTimeInAccountTimeWindow.First()) : 0); - } } diff --git a/src/RobinTTY.NordigenApiClient/release-notes.txt b/src/RobinTTY.NordigenApiClient/release-notes.txt index 6711509..4baa535 100644 --- a/src/RobinTTY.NordigenApiClient/release-notes.txt +++ b/src/RobinTTY.NordigenApiClient/release-notes.txt @@ -1,2 +1,2 @@ -This version improves many aspects of the library. Since this version contains breaking changes please check the release notes before updating. -For the full release notes please see: https://github.com/RobinTTY/NordigenApiClient/releases/tag/v10.0.0 \ No newline at end of file +Add the ability to check newly introduced rate limits in the GoCardless API. +Also see: https://bankaccountdata.zendesk.com/hc/en-gb/articles/11529584398236-Bank-API-Rate-Limits-and-Rate-Limit-Headers \ No newline at end of file From 5863063ebe609ea858faac322b2a7ae126f51c64 Mon Sep 17 00:00:00 2001 From: RobinTTY Date: Sun, 18 Aug 2024 15:20:24 +0200 Subject: [PATCH 3/5] Update documentation --- .../responses/api-rate-limits.md | 64 +++++++++++++++++++ .../responses/nordigen-api-response.md | 11 +++- docs/docs/handling-rate-limits.md | 31 +++++++++ docs/release-notes/v10_1_0.md | 9 +++ docs/sidebars.ts | 2 + .../Models/Errors/CreateAgreementError.cs | 1 - .../Models/Errors/CreateRequisitionError.cs | 1 - .../Models/Responses/ApiRateLimits.cs | 34 +++++----- .../RobinTTY.NordigenApiClient.csproj | 2 +- .../release-notes.txt | 2 +- 10 files changed, 135 insertions(+), 22 deletions(-) create mode 100644 docs/docs/api-reference/responses/api-rate-limits.md create mode 100644 docs/docs/handling-rate-limits.md create mode 100644 docs/release-notes/v10_1_0.md diff --git a/docs/docs/api-reference/responses/api-rate-limits.md b/docs/docs/api-reference/responses/api-rate-limits.md new file mode 100644 index 0000000..d164791 --- /dev/null +++ b/docs/docs/api-reference/responses/api-rate-limits.md @@ -0,0 +1,64 @@ +--- +title: ApiRateLimits +--- + +The `ApiRateLimits` class represents the rate limits of the GoCardless API. + +## Properties + +### `RequestLimit` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the maximum number of allowed requests within the defined time window. + +### `RemainingRequests` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the number of remaining requests you can make in the current time window. + +### `RemainingSecondsInTimeWindow` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the time remaining in the current time window (in seconds). + +### `RequestLimitAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the maximum number of allowed requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) within the defined time window. + +### `RemainingRequestsAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the number of remaining requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) you can make in the current time window. + +### `RemainingSecondsInTimeWindowAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the time remaining in the current time window (in seconds) for requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). + +## Constructor + +```csharp +public ApiRateLimits(int requestLimit, int remainingRequests, int remainingTimeInTimeWindow, + int maxAccountRequests, int remainingAccountRequests, int remainingTimeInAccountTimeWindow) +``` + +### Parameters + +#### `requestLimit` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the maximum number of allowed requests within the defined time window. + +#### `remainingRequests` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the number of remaining requests you can make in the current time window. + +#### `remainingSecondsInTimeWindow` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the time remaining in the current time window (in seconds). + +#### `requestLimitAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the maximum number of allowed requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) within the defined time window. + +#### `remainingRequestsAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the number of remaining requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) you can make in the current time window. + +#### `remainingSecondsInTimeWindowAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) + +Indicates the time remaining in the current time window (in seconds) for requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). diff --git a/docs/docs/api-reference/responses/nordigen-api-response.md b/docs/docs/api-reference/responses/nordigen-api-response.md index 617519d..9dfbe74 100644 --- a/docs/docs/api-reference/responses/nordigen-api-response.md +++ b/docs/docs/api-reference/responses/nordigen-api-response.md @@ -22,10 +22,15 @@ The result returned by the API. Null if the the HTTP response was not successful The error returned by the API. Null if the HTTP response was successful. +### `RateLimits` - [ApiRateLimits](/docs/api-reference/responses/api-rate-limits) + +The rate limits of the GoCardless API. + ## Constructor ```csharp -public NordigenApiResponse(HttpStatusCode statusCode, bool isSuccess, TResult? result, TError? apiError) +public NordigenApiResponse(HttpStatusCode statusCode, bool isSuccess, + TResult? result, TError? apiError, ApiRateLimits rateLimits) ``` ### Parameters @@ -46,6 +51,10 @@ The result returned by the API. Null if the the HTTP response was not successful The error returned by the API. Null if the HTTP response was successful. +#### `rateLimits` - [ApiRateLimits](/docs/api-reference/responses/api-rate-limits) + +The rate limits of the GoCardless API. + ## Handling the `NordigenApiResponse` type To learn more about how to best work with the `NordigenApiResponse` type see the [Handling API responses](/docs/handling-api-responses) guide. diff --git a/docs/docs/handling-rate-limits.md b/docs/docs/handling-rate-limits.md new file mode 100644 index 0000000..07ea907 --- /dev/null +++ b/docs/docs/handling-rate-limits.md @@ -0,0 +1,31 @@ +--- +title: Handling Rate Limits +--- + +The GoCardless API has [rate limits](https://bankaccountdata.zendesk.com/hc/en-gb/articles/11529637772188-Bank-Account-Data-API-Rate-Limits) depending on the endpoint you are using. With most endpoints you shouldn't run into problems since these limits are usually high enough for most uses. + +The [Accounts endpoint](/docs/api-reference/endpoints/accounts-endpoint) has very tight limitations though. It currently has a limit of 10 requests a day per access scope. That means 10 requests to each of the [details](/docs/api-reference/endpoints/accounts-endpoint#getaccountdetails), [balances](/docs/api-reference/endpoints/accounts-endpoint#getbalances) and [transactions](/docs/api-reference/endpoints/accounts-endpoint#gettransactions) endpoints. In the future this limit will be lowered to 4 per day (no date on this as of now). + +Unsuccessful requests to the API will count towards the general rate limits but not the more stringent limits of the [Accounts endpoint](/docs/api-reference/endpoints/accounts-endpoint). Only successful requests will count towards those. + +## Checking API rate limits + +You can check the rate limits as well as remaining requests with each request you make to the API. The property [`NordigenApiResponse.RateLimits`](/docs/api-reference/responses/nordigen-api-response#ratelimits---apiratelimits) will hold the returned information about the current API limits. + +You can check the limits as follows: + +```csharp +// Execute the request you want to make: +var bankAccountDetailsResponse = await client.AccountsEndpoint.GetAccountDetails(accountId); + +Console.WriteLine(bankAccountDetailsResponse.RateLimits.RequestLimit); +Console.WriteLine(bankAccountDetailsResponse.RateLimits.RemainingRequests); +Console.WriteLine(bankAccountDetailsResponse.RateLimits.RemainingSecondsInTimeWindow); +Console.WriteLine(bankAccountDetailsResponse.RateLimits.RequestLimitAccountsEndpoint); +Console.WriteLine(bankAccountDetailsResponse.RateLimits.RemainingRequestsAccountsEndpoint); +Console.WriteLine(bankAccountDetailsResponse.RateLimits.RemainingSecondsInTimeWindowAccountsEndpoint); +``` + +It's important to handle these limits so your applications user experience isn't degraded. Refreshing data from bank accounts should be handled consciously, so you don't use up all your requests in a short time frame and aren't able to update for the rest of the day. + +If you are a company with a contract with GoCardless you can probably get in contact with their team about increasing these limits. diff --git a/docs/release-notes/v10_1_0.md b/docs/release-notes/v10_1_0.md new file mode 100644 index 0000000..6fa977e --- /dev/null +++ b/docs/release-notes/v10_1_0.md @@ -0,0 +1,9 @@ +--- +slug: v10.1.0 +title: v10.1.0 +date: 2024-08-19T00:00 +--- + +Added the ability to check newly introduced rate limits in the GoCardless API. + +Please refer to the [documentation](/docs/handling-rate-limits) for more information. You can also see the [announcement from GoCardless](https://bankaccountdata.zendesk.com/hc/en-gb/articles/11529584398236-Bank-API-Rate-Limits-and-Rate-Limit-Headers). diff --git a/docs/sidebars.ts b/docs/sidebars.ts index eb9e3fa..2cb5bbe 100644 --- a/docs/sidebars.ts +++ b/docs/sidebars.ts @@ -6,6 +6,7 @@ const sidebars: SidebarsConfig = { "quickstart-guide", "handling-api-responses", "handling-authentication-tokens", + "handling-rate-limits", "using-a-different-base-address", "usage-with-older-dotnet-versions", "testing", @@ -38,6 +39,7 @@ const sidebars: SidebarsConfig = { "api-reference/responses/address", "api-reference/responses/agreement", "api-reference/responses/amount-currency-pair", + "api-reference/responses/api-rate-limits", "api-reference/responses/balance", "api-reference/responses/balance-type", "api-reference/responses/bank-account", diff --git a/src/RobinTTY.NordigenApiClient/Models/Errors/CreateAgreementError.cs b/src/RobinTTY.NordigenApiClient/Models/Errors/CreateAgreementError.cs index 09995d5..96a291a 100644 --- a/src/RobinTTY.NordigenApiClient/Models/Errors/CreateAgreementError.cs +++ b/src/RobinTTY.NordigenApiClient/Models/Errors/CreateAgreementError.cs @@ -1,6 +1,5 @@ using System.Text.Json.Serialization; using RobinTTY.NordigenApiClient.JsonConverters; -using RobinTTY.NordigenApiClient.Models.Requests; using RobinTTY.NordigenApiClient.Models.Responses; namespace RobinTTY.NordigenApiClient.Models.Errors; diff --git a/src/RobinTTY.NordigenApiClient/Models/Errors/CreateRequisitionError.cs b/src/RobinTTY.NordigenApiClient/Models/Errors/CreateRequisitionError.cs index 0472dd2..07276ae 100644 --- a/src/RobinTTY.NordigenApiClient/Models/Errors/CreateRequisitionError.cs +++ b/src/RobinTTY.NordigenApiClient/Models/Errors/CreateRequisitionError.cs @@ -1,6 +1,5 @@ using System.Text.Json.Serialization; using RobinTTY.NordigenApiClient.JsonConverters; -using RobinTTY.NordigenApiClient.Models.Requests; using RobinTTY.NordigenApiClient.Models.Responses; namespace RobinTTY.NordigenApiClient.Models.Errors; diff --git a/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs index a6609f6..23a683a 100644 --- a/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs +++ b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs @@ -24,46 +24,46 @@ public class ApiRateLimits /// Indicates the maximum number of allowed requests to the /// within the defined time window. /// - public int MaxAccountRequests { get; set; } + public int RequestLimitAccountsEndpoint { get; set; } /// /// Indicates the number of remaining requests to the /// you can make in the current time window. /// - public int RemainingAccountRequests { get; set; } + public int RemainingRequestsAccountsEndpoint { get; set; } /// /// Indicates the time remaining in the current time window (in seconds) for requests /// to the . /// - public int RemainingSecondsInAccountTimeWindow { get; set; } + public int RemainingSecondsInTimeWindowAccountsEndpoint { get; set; } /// /// Creates a new instance of . /// /// Indicates the maximum number of allowed requests within the defined time window. /// Indicates the number of remaining requests you can make in the current time window. - /// Indicates the time remaining in the current time window (in seconds). - /// Indicates the maximum number of allowed requests to the + /// Indicates the time remaining in the current time window (in seconds). + /// Indicates the maximum number of allowed requests to the /// within the defined time window. - /// Indicates the number of remaining requests to the + /// Indicates the number of remaining requests to the /// you can make in the current time window. - /// Indicates the time remaining in the current time window (in seconds) for requests + /// Indicates the time remaining in the current time window (in seconds) for requests /// to the . - public ApiRateLimits(int requestLimit, int remainingRequests, int remainingTimeInTimeWindow, int maxAccountRequests, - int remainingAccountRequests, int remainingTimeInAccountTimeWindow) + public ApiRateLimits(int requestLimit, int remainingRequests, int remainingSecondsInTimeWindow, int requestLimitAccountsEndpoint, + int remainingRequestsAccountsEndpoint, int remainingSecondsInTimeWindowAccountsEndpoint) { RequestLimit = requestLimit; RemainingRequests = remainingRequests; - RemainingSecondsInTimeWindow = remainingTimeInTimeWindow; - MaxAccountRequests = maxAccountRequests; - RemainingAccountRequests = remainingAccountRequests; - RemainingSecondsInAccountTimeWindow = remainingTimeInAccountTimeWindow; + RemainingSecondsInTimeWindow = remainingSecondsInTimeWindow; + RequestLimitAccountsEndpoint = requestLimitAccountsEndpoint; + RemainingRequestsAccountsEndpoint = remainingRequestsAccountsEndpoint; + RemainingSecondsInTimeWindowAccountsEndpoint = remainingSecondsInTimeWindowAccountsEndpoint; } /// /// Creates a new instance of . /// /// The headers of the HTTP response containing the rate limit information. - public ApiRateLimits(HttpResponseHeaders headers) + public ApiRateLimits(HttpHeaders headers) { headers.TryGetValues("HTTP_X_RATELIMIT_LIMIT", out var requestLimitInTimeWindow); headers.TryGetValues("HTTP_X_RATELIMIT_REMAINING", out var remainingRequestsInTimeWindow); @@ -75,8 +75,8 @@ public ApiRateLimits(HttpResponseHeaders headers) RequestLimit = requestLimitInTimeWindow != null ? int.Parse(requestLimitInTimeWindow.First()) : 0; RemainingRequests = remainingRequestsInTimeWindow != null ? int.Parse(remainingRequestsInTimeWindow.First()) : 0; RemainingSecondsInTimeWindow = remainingTimeInTimeWindow != null ? int.Parse(remainingTimeInTimeWindow.First()) : 0; - MaxAccountRequests = maxAccountRequestsInTimeWindow != null ? int.Parse(maxAccountRequestsInTimeWindow.First()) : 0; - RemainingAccountRequests = remainingAccountRequestsInTimeWindow != null ? int.Parse(remainingAccountRequestsInTimeWindow.First()) : 0; - RemainingSecondsInAccountTimeWindow = remainingTimeInAccountTimeWindow != null ? int.Parse(remainingTimeInAccountTimeWindow.First()) : 0; + RequestLimitAccountsEndpoint = maxAccountRequestsInTimeWindow != null ? int.Parse(maxAccountRequestsInTimeWindow.First()) : 0; + RemainingRequestsAccountsEndpoint = remainingAccountRequestsInTimeWindow != null ? int.Parse(remainingAccountRequestsInTimeWindow.First()) : 0; + RemainingSecondsInTimeWindowAccountsEndpoint = remainingTimeInAccountTimeWindow != null ? int.Parse(remainingTimeInAccountTimeWindow.First()) : 0; } } diff --git a/src/RobinTTY.NordigenApiClient/RobinTTY.NordigenApiClient.csproj b/src/RobinTTY.NordigenApiClient/RobinTTY.NordigenApiClient.csproj index 956ad93..f783d9f 100644 --- a/src/RobinTTY.NordigenApiClient/RobinTTY.NordigenApiClient.csproj +++ b/src/RobinTTY.NordigenApiClient/RobinTTY.NordigenApiClient.csproj @@ -16,7 +16,7 @@ Nordigen; API; client $([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/release-notes.txt")) MIT - 10.0.0 + 10.1.0 true snupkg 12f53312-dcef-47c5-bc2e-0ce6f74609a6 diff --git a/src/RobinTTY.NordigenApiClient/release-notes.txt b/src/RobinTTY.NordigenApiClient/release-notes.txt index 4baa535..4634324 100644 --- a/src/RobinTTY.NordigenApiClient/release-notes.txt +++ b/src/RobinTTY.NordigenApiClient/release-notes.txt @@ -1,2 +1,2 @@ -Add the ability to check newly introduced rate limits in the GoCardless API. +Added the ability to check newly introduced rate limits in the GoCardless API. Also see: https://bankaccountdata.zendesk.com/hc/en-gb/articles/11529584398236-Bank-API-Rate-Limits-and-Rate-Limit-Headers \ No newline at end of file From 8e4477c4bc8812b61ff8c5ffdd76e1b10d8a18f2 Mon Sep 17 00:00:00 2001 From: RobinTTY Date: Mon, 19 Aug 2024 21:10:43 +0200 Subject: [PATCH 4/5] Make ApiRateLimits properties nullable --- README.md | 2 +- .../responses/api-rate-limits.md | 36 ++++++------- .../.idea/.gitignore | 13 +++++ .../.idea/.name | 1 + .../.idea/encodings.xml | 4 ++ .../.idea/indexLayout.xml | 8 +++ .../.idea/vcs.xml | 6 +++ .../Models/Responses/ApiRateLimits.cs | 51 ++++++++++--------- 8 files changed, 79 insertions(+), 42 deletions(-) create mode 100644 src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.gitignore create mode 100644 src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.name create mode 100644 src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/encodings.xml create mode 100644 src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/indexLayout.xml create mode 100644 src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/vcs.xml diff --git a/README.md b/README.md index 257cf22..8199f93 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

# NordigenApiClient diff --git a/docs/docs/api-reference/responses/api-rate-limits.md b/docs/docs/api-reference/responses/api-rate-limits.md index d164791..af22d8d 100644 --- a/docs/docs/api-reference/responses/api-rate-limits.md +++ b/docs/docs/api-reference/responses/api-rate-limits.md @@ -8,27 +8,27 @@ The `ApiRateLimits` class represents the rate limits of the GoCardless API. ### `RequestLimit` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) -Indicates the maximum number of allowed requests within the defined time window. +Indicates the maximum number of allowed requests within the defined time window. Usually populated in every response. ### `RemainingRequests` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) -Indicates the number of remaining requests you can make in the current time window. +Indicates the number of remaining requests you can make in the current time window. Usually populated in every response. ### `RemainingSecondsInTimeWindow` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) -Indicates the time remaining in the current time window (in seconds). +Indicates the time remaining in the current time window (in seconds). Usually populated in every response. ### `RequestLimitAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) -Indicates the maximum number of allowed requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) within the defined time window. +Indicates the maximum number of allowed requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) within the defined time window. Only populated in responses from the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). ### `RemainingRequestsAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) -Indicates the number of remaining requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) you can make in the current time window. +Indicates the number of remaining requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) you can make in the current time window. Only populated in responses from the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). ### `RemainingSecondsInTimeWindowAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) -Indicates the time remaining in the current time window (in seconds) for requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). +Indicates the time remaining in the current time window (in seconds) for requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). Only populated in responses from the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). ## Constructor @@ -39,26 +39,26 @@ public ApiRateLimits(int requestLimit, int remainingRequests, int remainingTimeI ### Parameters -#### `requestLimit` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) +#### `requestLimit` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32)? -Indicates the maximum number of allowed requests within the defined time window. +Indicates the maximum number of allowed requests within the defined time window. Usually populated in every response. -#### `remainingRequests` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) +#### `remainingRequests` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32)? -Indicates the number of remaining requests you can make in the current time window. +Indicates the number of remaining requests you can make in the current time window. Usually populated in every response. -#### `remainingSecondsInTimeWindow` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) +#### `remainingSecondsInTimeWindow` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32)? -Indicates the time remaining in the current time window (in seconds). +Indicates the time remaining in the current time window (in seconds). Usually populated in every response. -#### `requestLimitAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) +#### `requestLimitAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32)? -Indicates the maximum number of allowed requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) within the defined time window. +Indicates the maximum number of allowed requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) within the defined time window. Only populated in responses from the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). -#### `remainingRequestsAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) +#### `remainingRequestsAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32)? -Indicates the number of remaining requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) you can make in the current time window. +Indicates the number of remaining requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint) you can make in the current time window. Only populated in responses from the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). -#### `remainingSecondsInTimeWindowAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32) +#### `remainingSecondsInTimeWindowAccountsEndpoint` - [int](https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-int32)? -Indicates the time remaining in the current time window (in seconds) for requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). +Indicates the time remaining in the current time window (in seconds) for requests to the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). Only populated in responses from the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint). diff --git a/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.gitignore b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.gitignore new file mode 100644 index 0000000..6898b60 --- /dev/null +++ b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/.idea.RobinTTY.NordigenApiClient.iml +/contentModel.xml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.name b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.name new file mode 100644 index 0000000..611320e --- /dev/null +++ b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/.name @@ -0,0 +1 @@ +RobinTTY.NordigenApiClient \ No newline at end of file diff --git a/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/encodings.xml b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/indexLayout.xml b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/vcs.xml b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/src/RobinTTY.NordigenApiClient.Tests/.idea/.idea.RobinTTY.NordigenApiClient.dir/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs index 23a683a..f234d77 100644 --- a/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs +++ b/src/RobinTTY.NordigenApiClient/Models/Responses/ApiRateLimits.cs @@ -10,31 +10,34 @@ public class ApiRateLimits { /// /// Indicates the maximum number of allowed requests within the defined time window. + /// Usually populated in every response. /// - public int RequestLimit { get; set; } + public int? RequestLimit { get; set; } /// /// Indicates the number of remaining requests you can make in the current time window. + /// Usually populated in every response. /// - public int RemainingRequests { get; set; } + public int? RemainingRequests { get; set; } /// /// Indicates the time remaining in the current time window (in seconds). + /// Usually populated in every response. /// - public int RemainingSecondsInTimeWindow { get; set; } + public int? RemainingSecondsInTimeWindow { get; set; } /// /// Indicates the maximum number of allowed requests to the - /// within the defined time window. + /// within the defined time window. Only populated in responses from the . /// - public int RequestLimitAccountsEndpoint { get; set; } + public int? RequestLimitAccountsEndpoint { get; set; } /// /// Indicates the number of remaining requests to the - /// you can make in the current time window. + /// you can make in the current time window. Only populated in responses from the . /// - public int RemainingRequestsAccountsEndpoint { get; set; } + public int? RemainingRequestsAccountsEndpoint { get; set; } /// /// Indicates the time remaining in the current time window (in seconds) for requests - /// to the . + /// to the . Only populated in responses from the . /// - public int RemainingSecondsInTimeWindowAccountsEndpoint { get; set; } + public int? RemainingSecondsInTimeWindowAccountsEndpoint { get; set; } /// /// Creates a new instance of . @@ -48,8 +51,8 @@ public class ApiRateLimits /// you can make in the current time window. /// Indicates the time remaining in the current time window (in seconds) for requests /// to the . - public ApiRateLimits(int requestLimit, int remainingRequests, int remainingSecondsInTimeWindow, int requestLimitAccountsEndpoint, - int remainingRequestsAccountsEndpoint, int remainingSecondsInTimeWindowAccountsEndpoint) + public ApiRateLimits(int? requestLimit, int? remainingRequests, int? remainingSecondsInTimeWindow, int? requestLimitAccountsEndpoint, + int? remainingRequestsAccountsEndpoint, int? remainingSecondsInTimeWindowAccountsEndpoint) { RequestLimit = requestLimit; RemainingRequests = remainingRequests; @@ -65,18 +68,20 @@ public ApiRateLimits(int requestLimit, int remainingRequests, int remainingSecon /// The headers of the HTTP response containing the rate limit information. public ApiRateLimits(HttpHeaders headers) { - headers.TryGetValues("HTTP_X_RATELIMIT_LIMIT", out var requestLimitInTimeWindow); - headers.TryGetValues("HTTP_X_RATELIMIT_REMAINING", out var remainingRequestsInTimeWindow); - headers.TryGetValues("HTTP_X_RATELIMIT_RESET", out var remainingTimeInTimeWindow); - headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_LIMIT", out var maxAccountRequestsInTimeWindow); - headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_REMAINING", out var remainingAccountRequestsInTimeWindow); - headers.TryGetValues("HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_RESET", out var remainingTimeInAccountTimeWindow); + RequestLimit = TryParseApiLimit(headers, "HTTP_X_RATELIMIT_LIMIT"); + RemainingRequests = TryParseApiLimit(headers, "HTTP_X_RATELIMIT_REMAINING"); + RemainingSecondsInTimeWindow = TryParseApiLimit(headers, "HTTP_X_RATELIMIT_RESET"); + RequestLimitAccountsEndpoint = TryParseApiLimit(headers, "HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_LIMIT"); + RemainingRequestsAccountsEndpoint = TryParseApiLimit(headers, "HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_REMAINING"); + RemainingSecondsInTimeWindowAccountsEndpoint = TryParseApiLimit(headers, "HTTP_X_RATELIMIT_ACCOUNT_SUCCESS_RESET"); + } - RequestLimit = requestLimitInTimeWindow != null ? int.Parse(requestLimitInTimeWindow.First()) : 0; - RemainingRequests = remainingRequestsInTimeWindow != null ? int.Parse(remainingRequestsInTimeWindow.First()) : 0; - RemainingSecondsInTimeWindow = remainingTimeInTimeWindow != null ? int.Parse(remainingTimeInTimeWindow.First()) : 0; - RequestLimitAccountsEndpoint = maxAccountRequestsInTimeWindow != null ? int.Parse(maxAccountRequestsInTimeWindow.First()) : 0; - RemainingRequestsAccountsEndpoint = remainingAccountRequestsInTimeWindow != null ? int.Parse(remainingAccountRequestsInTimeWindow.First()) : 0; - RemainingSecondsInTimeWindowAccountsEndpoint = remainingTimeInAccountTimeWindow != null ? int.Parse(remainingTimeInAccountTimeWindow.First()) : 0; + private static int? TryParseApiLimit(HttpHeaders headers, string headerName) + { + headers.TryGetValues(headerName, out var values); + var firstHeaderValue = values?.FirstOrDefault(); + var parseSuccess = int.TryParse(firstHeaderValue, out var limitValue); + + return parseSuccess ? limitValue : null; } } From 5b7a16ee25726de36e934ddf9ce592e908494ec8 Mon Sep 17 00:00:00 2001 From: RobinTTY Date: Mon, 19 Aug 2024 21:33:43 +0200 Subject: [PATCH 5/5] Add full changelog link to release notes --- docs/release-notes/v10_1_0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/v10_1_0.md b/docs/release-notes/v10_1_0.md index 6fa977e..e8cb6a4 100644 --- a/docs/release-notes/v10_1_0.md +++ b/docs/release-notes/v10_1_0.md @@ -7,3 +7,5 @@ date: 2024-08-19T00:00 Added the ability to check newly introduced rate limits in the GoCardless API. Please refer to the [documentation](/docs/handling-rate-limits) for more information. You can also see the [announcement from GoCardless](https://bankaccountdata.zendesk.com/hc/en-gb/articles/11529584398236-Bank-API-Rate-Limits-and-Rate-Limit-Headers). + +**Full Changelog**: [v10.0.0...v10.1.0](https://github.com/RobinTTY/NordigenApiClient/compare/v10.0.0...v10.1.0)