Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
RobinTTY committed Dec 8, 2024
2 parents 7a722f6 + e24984f commit 89f69ba
Show file tree
Hide file tree
Showing 101 changed files with 578 additions and 229 deletions.
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
<p align="center">
<img src="docs/static/img/nordigen-api-client-logo.png" width="30%">
<img src="https://raw.githubusercontent.com/RobinTTY/NordigenApiClient/main/docs/static/img/nordigen-api-client-logo.png" width="30%">
</p>

# NordigenApiClient

This library provides a .NET client for the [GoCardless Bank Account Data API](https://gocardless.com/bank-account-data/) (formerly Nordigen API). The following API endpoints are supported:
This library provides a .NET client for
the [GoCardless Bank Account Data API](https://gocardless.com/bank-account-data/) (formerly Nordigen API). The following
API endpoints are supported:

- Token
- Institutions
- Agreements
- Requisitions
- Accounts

You can get started with the Quickstart Guide below or take a look at the [full documentation](https://robintty.github.io/NordigenApiClient/). You can find the nuget package [here](https://www.nuget.org/packages/RobinTTY.NordigenApiClient).
You can get started with the Quickstart Guide below or take a look at
the [full documentation](https://robintty.github.io/NordigenApiClient/). You can find the nuget
package [here](https://www.nuget.org/packages/RobinTTY.NordigenApiClient).

## Quickstart Guide

Expand Down Expand Up @@ -61,11 +65,13 @@ You can get started with the Quickstart Guide below or take a look at the [full
Console.WriteLine($"Requisition couldn't be created: {requisitionResponse.Error.Summary}");
```

5. You will now need to accept the end user agreement by following the authentication link you got in the last step. The authentication flow will roughly look like this:
5. You will now need to accept the end user agreement by following the authentication link you got in the last step. The
authentication flow will roughly look like this:

![authentication-flow](docs/static/img/authentication_flow.png)

6. Now that you have accepted the agreement we once again need to retrieve the requisition we created in step 4. This time the response will include the accounts you are now able to access.
6. Now that you have accepted the agreement we once again need to retrieve the requisition we created in step 4. This
time the response will include the accounts you are now able to access.

```cs
var requisitionId = "your-requisition-id";
Expand All @@ -79,7 +85,8 @@ You can get started with the Quickstart Guide below or take a look at the [full
Console.WriteLine($"Accounts couldn't be retrieved: {accountsResponse.Error.Summary}");
```

7. Now you can retrieve details about your bank account and the balances/transactions using the account ID(s) we just acquired:
7. Now you can retrieve details about your bank account and the balances/transactions using the account ID(s) we just
acquired:

```cs
var accountId = "your-account-id";
Expand Down Expand Up @@ -110,4 +117,6 @@ You can get started with the Quickstart Guide below or take a look at the [full
});
```

That's it! You are now able to retrieve the account details, balances and transactions of your bank account. If you wanna learn more about this library please refer to the [full documentation](https://robintty.github.io/NordigenApiClient/).
That's it! You are now able to retrieve the account details, balances and transactions of your bank account. If you
wanna learn more about this library please refer to
the [full documentation](https://robintty.github.io/NordigenApiClient/).
64 changes: 64 additions & 0 deletions docs/docs/api-reference/responses/api-rate-limits.md
Original file line number Diff line number Diff line change
@@ -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. 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. 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). 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. 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. 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). Only populated in responses from 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. 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. 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). 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. 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. 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). Only populated in responses from the [AccountsEndpoint](/docs/api-reference/endpoints/accounts-endpoint).
11 changes: 10 additions & 1 deletion docs/docs/api-reference/responses/nordigen-api-response.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
31 changes: 31 additions & 0 deletions docs/docs/handling-rate-limits.md
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions docs/release-notes/v10_0_0.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public async Task<NordigenApiResponse<List<Institution>, 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)
11 changes: 11 additions & 0 deletions docs/release-notes/v10_1_0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
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).

**Full Changelog**: [v10.0.0...v10.1.0](https://github.com/RobinTTY/NordigenApiClient/compare/v10.0.0...v10.1.0)
2 changes: 2 additions & 0 deletions docs/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@
Console.WriteLine($"Remittance: {transaction.RemittanceInformationUnstructured}");
Console.WriteLine($"Booking date:{transaction.ValueDate}");
Console.WriteLine($"Amount: {transactionAmount.Amount} {transactionAmount.Currency}");
});
});

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ public void CheckForTokenExpiry()
Assert.That(token.IsExpired(diffInvalid), Is.True);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ public void DeserializeEnum<T>(string descriptor, T expectedDeserializedValue)
var enumValue = JsonSerializer.Deserialize<T>($"\"{descriptor}\"");
Assert.That(enumValue, Is.EqualTo(expectedDeserializedValue));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public void Setup()
#region RequestsWithSuccessfulResponse

/// <summary>
/// Tests that <see cref="NordigenClient.JsonWebTokenPair" /> is populated after the first authenticated request is made.
/// Tests that <see cref="NordigenClient.JsonWebTokenPair" /> is populated after the first authenticated request is
/// made.
/// </summary>
[Test]
public async Task CheckValidTokensAfterRequest()
Expand Down Expand Up @@ -105,4 +106,4 @@ public async Task ExecuteRequestWithUnauthorizedIp()
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ public async Task GetTransactionRangeInFuture()
}

/// <summary>
/// Tests the retrieval of transactions within a specific time frame where the date range is incorrect, since the endDate is before the startDate. This should throw an exception.
/// Tests the retrieval of transactions within a specific time frame where the date range is incorrect, since the
/// endDate is before the startDate. This should throw an exception.
/// </summary>
[Test]
public void GetTransactionRangeWithIncorrectRange()
Expand All @@ -237,4 +238,4 @@ await _apiClient.AccountsEndpoint.GetTransactions(_accountId, DateOnly.FromDateT
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ await _apiClient.AgreementsEndpoint.CreateAgreement(null!, uint.MaxValue, uint.M
}

/// <summary>
/// Tests the creation of an end user agreement with invalid accessValidForDays and maxHistoricalDays for that particular institution.
/// Tests the creation of an end user agreement with invalid accessValidForDays and maxHistoricalDays for that
/// particular institution.
/// </summary>
[Test]
public async Task CreateAgreementWithInvalidArgumentsForInstitution()
Expand Down Expand Up @@ -237,11 +238,12 @@ await _apiClient.AgreementsEndpoint.CreateAgreement("PKO_BPKOPLPW",

Assert.That(response.Error!.AccessScopeError!.Detail,
Is.EqualTo("For this institution the following scopes are required together: ['details', 'balances']"));
Assert.That(response.Error!.AccessScopeError.Summary, Is.EqualTo("Institution access scope dependencies error"));
Assert.That(response.Error!.AccessScopeError.Summary,
Is.EqualTo("Institution access scope dependencies error"));

Assert.That(new[] {response.Error!.InstitutionIdError, response.Error!.AgreementError}, Has.All.Null);
});
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,4 @@ public async Task GetNonExistingInstitution()
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,4 @@ await _apiClient.RequisitionsEndpoint.CreateRequisition("", redirect, agreementI
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ public async Task ReuseExpiredToken()
}

/// <summary>
/// Tests whether the <see cref="NordigenClient.TokenPairUpdated"/> event is raised when the token pair is updated
/// automatically by the client itself.
/// Tests whether the <see cref="NordigenClient.TokenPairUpdated" /> event is raised when the token pair is updated
/// automatically by the client itself.
/// </summary>
[Test]
public async Task TokenPairUpdateIsRaisedOnInternalUpdate()
Expand All @@ -68,10 +68,10 @@ public async Task TokenPairUpdateIsRaisedOnInternalUpdate()
Assert.That(eventArgs.JsonWebTokenPair.RefreshToken.EncodedToken, Is.Not.Empty);
});
}

/// <summary>
/// Tests whether the <see cref="NordigenClient.TokenPairUpdated"/> event is raised when the token pair is updated
/// by the user.
/// Tests whether the <see cref="NordigenClient.TokenPairUpdated" /> event is raised when the token pair is updated
/// by the user.
/// </summary>
[Test]
public void TokenPairUpdateIsRaisedOnManualUpdate()
Expand Down Expand Up @@ -117,4 +117,4 @@ public async Task GetTokenWithInvalidCredentials()
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ private async Task ExecuteExampleRequest(NordigenClient apiClient)
}

#endregion
}
}
Loading

0 comments on commit 89f69ba

Please sign in to comment.