feat: Use JsonSerializationContext for all types, enable trimming (#14)
This commit is contained in:
+25
-5
@@ -75,12 +75,32 @@ public static class ServiceCollectionExtensions
|
||||
.AddSingleton<NordigenTokenCache>()
|
||||
.AddSingleton<NordigenJsonSerializerOptions>()
|
||||
.AddTransient<INordigenClient, NordigenClient>()
|
||||
.AddTransient<IAccountClient, AccountClient>()
|
||||
.AddTransient<IAgreementClient, AgreementClient>()
|
||||
.AddTransient<IInstitutionClient, InstitutionClient>()
|
||||
.AddTransient<IRequisitionClient, RequisitionClient>()
|
||||
.AddTransient<IAccountClient, AccountClient>(provider =>
|
||||
{
|
||||
var httpClient = provider.GetRequiredService<IHttpClientFactory>().CreateClient(NordigenOptions.SectionName);
|
||||
var options = provider.GetRequiredService<NordigenJsonSerializerOptions>();
|
||||
return new(httpClient, options);
|
||||
})
|
||||
.AddTransient<IAgreementClient, AgreementClient>(provider =>
|
||||
{
|
||||
var httpClient = provider.GetRequiredService<IHttpClientFactory>().CreateClient(NordigenOptions.SectionName);
|
||||
var options = provider.GetRequiredService<NordigenJsonSerializerOptions>();
|
||||
return new(httpClient, options);
|
||||
})
|
||||
.AddTransient<IInstitutionClient, InstitutionClient>(provider =>
|
||||
{
|
||||
var httpClient = provider.GetRequiredService<IHttpClientFactory>().CreateClient(NordigenOptions.SectionName);
|
||||
var options = provider.GetRequiredService<NordigenJsonSerializerOptions>();
|
||||
return new(httpClient, options);
|
||||
})
|
||||
.AddTransient<IRequisitionClient, RequisitionClient>(provider =>
|
||||
{
|
||||
var httpClient = provider.GetRequiredService<IHttpClientFactory>().CreateClient(NordigenOptions.SectionName);
|
||||
var options = provider.GetRequiredService<NordigenJsonSerializerOptions>();
|
||||
return new(httpClient, options);
|
||||
})
|
||||
.AddTransient(provider => provider.GetRequiredService<IOptionsMonitor<NordigenOptions>>().CurrentValue)
|
||||
.AddHttpClient<NordigenHttpClient>(ConfigureNordigenClient)
|
||||
.AddHttpClient(NordigenOptions.SectionName, ConfigureNordigenClient)
|
||||
.AddHttpMessageHandler<TokenDelegatingHandler>();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,16 +12,25 @@ using VMelnalksnis.NordigenDotNet.Institutions;
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>Information about the account record, such as the processing status and IBAN.</summary>
|
||||
/// <param name="Id">The ID of this Account, used to refer to this account in other API calls.</param>
|
||||
/// <param name="Created">The point in time when the account object was created.</param>
|
||||
/// <param name="LastAccessed">The point in time when the account object was last accessed.</param>
|
||||
/// <param name="Iban">The account IBAN.</param>
|
||||
/// <param name="InstitutionId">The id of the <see cref="Institution"/> associated with the account.</param>
|
||||
/// <param name="Status">The processing status of this account.</param>
|
||||
public record Account(
|
||||
Guid Id,
|
||||
Instant Created,
|
||||
[property: JsonPropertyName("last_accessed")] Instant LastAccessed,
|
||||
string Iban,
|
||||
[property: JsonPropertyName("institution_id")] string InstitutionId,
|
||||
AccountStatus Status);
|
||||
public record Account
|
||||
{
|
||||
/// <summary>Gets or sets the id of this Account, used to refer to this account in other API calls.</summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the point in time when the account object was created.</summary>
|
||||
public Instant Created { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the point in time when the account object was last accessed.</summary>
|
||||
[JsonPropertyName("last_accessed")]
|
||||
public Instant LastAccessed { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the account IBAN.</summary>
|
||||
public string Iban { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the id of the <see cref="Institution"/> associated with the account.</summary>
|
||||
[JsonPropertyName("institution_id")]
|
||||
public string InstitutionId { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the processing status of this account.</summary>
|
||||
public AccountStatus Status { get; set; }
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -14,30 +17,29 @@ namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
/// <inheritdoc />
|
||||
public sealed class AccountClient : IAccountClient
|
||||
{
|
||||
private readonly NordigenHttpClient _nordigenHttpClient;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly NordigenSerializationContext _context;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="AccountClient"/> class.</summary>
|
||||
/// <param name="nordigenHttpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
public AccountClient(NordigenHttpClient nordigenHttpClient)
|
||||
/// <param name="httpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
/// <param name="serializerOptions">Nordigen specific instance of <see cref="JsonSerializerOptions"/>.</param>
|
||||
public AccountClient(HttpClient httpClient, NordigenJsonSerializerOptions serializerOptions)
|
||||
{
|
||||
_nordigenHttpClient = nordigenHttpClient;
|
||||
_httpClient = httpClient;
|
||||
_context = serializerOptions.Context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Account> Get(Guid id, CancellationToken cancellationToken = default)
|
||||
public Task<Account> Get(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var account = await _nordigenHttpClient
|
||||
.Get<Account>(Routes.Accounts.IdUri(id), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return account!;
|
||||
return _httpClient.GetFromJsonAsync(Routes.Accounts.IdUri(id), _context.Account, cancellationToken)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<Balance>> GetBalances(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var balances = await _nordigenHttpClient
|
||||
.Get<BalancesWrapper>(Routes.Accounts.BalancesUri(id), cancellationToken)
|
||||
var balances = await _httpClient
|
||||
.GetFromJsonAsync(Routes.Accounts.BalancesUri(id), _context.BalancesWrapper, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return balances!.Balances;
|
||||
@@ -46,8 +48,8 @@ public sealed class AccountClient : IAccountClient
|
||||
/// <inheritdoc />
|
||||
public async Task<AccountDetails> GetDetails(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var details = await _nordigenHttpClient
|
||||
.Get<AccountDetailsWrapper>(Routes.Accounts.DetailsUri(id), cancellationToken)
|
||||
var details = await _httpClient
|
||||
.GetFromJsonAsync(Routes.Accounts.DetailsUri(id), _context.AccountDetailsWrapper, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return details!.Account;
|
||||
@@ -59,10 +61,8 @@ public sealed class AccountClient : IAccountClient
|
||||
Interval? interval = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var uri = Routes.Accounts.TransactionsUri(id, interval);
|
||||
|
||||
var transactions = await _nordigenHttpClient
|
||||
.Get<TransactionsWrapper>(uri, cancellationToken)
|
||||
var transactions = await _httpClient
|
||||
.GetFromJsonAsync(Routes.Accounts.TransactionsUri(id, interval), _context.TransactionsWrapper, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return transactions!.Transactions;
|
||||
|
||||
@@ -5,13 +5,34 @@
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>Additional details of an account.</summary>
|
||||
public record AccountDetails(
|
||||
string ResourceId,
|
||||
string Iban,
|
||||
string Currency,
|
||||
string OwnerName,
|
||||
string Name,
|
||||
string Product,
|
||||
string CashAccountType);
|
||||
public record AccountDetails
|
||||
{
|
||||
/// <summary>Gets or sets the account id of the given account in the financial institution.</summary>
|
||||
public string ResourceId { get; set; } = null!;
|
||||
|
||||
internal record AccountDetailsWrapper(AccountDetails Account);
|
||||
/// <summary>Gets or sets the IBAN of the account.</summary>
|
||||
public string? Iban { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a ISO 4217 currency code.</summary>
|
||||
public string Currency { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the legal account owner.
|
||||
/// If there is more than one owner, then e.g. two names might be noted here.
|
||||
/// For a corporate account, the corporate name is used for this attribute.</summary>
|
||||
public string? OwnerName { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the name of the account, as assigned by the financial institution.</summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>Gets or sets product Name of the Bank for this account, proprietary definition.</summary>
|
||||
public string? Product { get; set; }
|
||||
|
||||
/// <summary>Gets or sets externalCashAccountType1Code from ISO 20022.</summary>
|
||||
public string? CashAccountType { get; set; }
|
||||
}
|
||||
|
||||
internal class AccountDetailsWrapper
|
||||
{
|
||||
public AccountDetails Account { get; set; } = null!;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>An amount in a specific currency.</summary>
|
||||
/// <param name="Currency">A ISO 4217 currency code.</param>
|
||||
/// <param name="Amount">The amount.</param>
|
||||
public record AmountInCurrency(string Currency, decimal Amount);
|
||||
public record AmountInCurrency
|
||||
{
|
||||
/// <summary>Gets or sets a ISO 4217 currency code.</summary>
|
||||
public string Currency { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the amount.</summary>
|
||||
public decimal Amount { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,18 +6,25 @@ using System.Collections.Generic;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
#pragma warning disable SA1623
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>Account balance.</summary>
|
||||
/// <param name="BalanceAmount">The balance amount.</param>
|
||||
/// <param name="BalanceType">The balance type.</param>
|
||||
/// <param name="CreditLimitIncluded">Whether the credit limit is included in <paramref name="BalanceAmount"/>.</param>
|
||||
public record Balance(AmountInCurrency BalanceAmount, string BalanceType, bool CreditLimitIncluded)
|
||||
public record Balance
|
||||
{
|
||||
/// <summary>The date on which the balance was calculated.</summary>
|
||||
public LocalDate? ReferenceDate { get; init; }
|
||||
/// <summary>Gets or sets the balance amount.</summary>
|
||||
public AmountInCurrency BalanceAmount { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the balance type.</summary>
|
||||
public string BalanceType { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether whether the credit limit is included in <see cref="BalanceAmount"/>.</summary>
|
||||
public bool CreditLimitIncluded { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the date on which the balance was calculated.</summary>
|
||||
public LocalDate? ReferenceDate { get; set; }
|
||||
}
|
||||
|
||||
internal record BalancesWrapper(List<Balance> Balances);
|
||||
internal class BalancesWrapper
|
||||
{
|
||||
public List<Balance> Balances { get; set; } = null!;
|
||||
}
|
||||
|
||||
@@ -6,50 +6,45 @@ using NodaTime;
|
||||
|
||||
using VMelnalksnis.NordigenDotNet.Institutions;
|
||||
|
||||
#pragma warning disable SA1623
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>A transaction that has been booked - posted to an account on the account servicer's books.</summary>
|
||||
/// <param name="TransactionAmount">The amount transferred in this transaction.</param>
|
||||
/// <param name="UnstructuredInformation">Unstructured information about the transaction, usually added by the debtor.</param>
|
||||
/// <param name="TransactionId">A unique transaction id created by the <see cref="Institution"/>.</param>
|
||||
/// <param name="BookingDate">The date when an entry is posted to an account on the account servicer's books.</param>
|
||||
public record BookedTransaction(
|
||||
AmountInCurrency TransactionAmount,
|
||||
string UnstructuredInformation,
|
||||
string TransactionId,
|
||||
LocalDate BookingDate)
|
||||
: Transaction(TransactionAmount, UnstructuredInformation)
|
||||
public record BookedTransaction : Transaction
|
||||
{
|
||||
/// <summary>The name of the counterparty that sends <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public string? DebtorName { get; init; }
|
||||
/// <summary>Gets or sets a unique transaction id created by the <see cref="Institution"/>.</summary>
|
||||
public string TransactionId { get; set; } = null!;
|
||||
|
||||
/// <summary>The account of the counterparty that sends <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public TransactionAccount? DebtorAccount { get; init; }
|
||||
/// <summary>Gets or sets the date when an entry is posted to an account on the account servicer's books.</summary>
|
||||
public LocalDate BookingDate { get; set; }
|
||||
|
||||
/// <summary>The name of the counterparty that receives <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public string? CreditorName { get; init; }
|
||||
/// <summary>Gets or sets the name of the counterparty that sends <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public string? DebtorName { get; set; }
|
||||
|
||||
/// <summary>The account of the counterparty that receives <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public TransactionAccount? CreditorAccount { get; init; }
|
||||
/// <summary>Gets or sets the account of the counterparty that sends <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public TransactionAccount? DebtorAccount { get; set; }
|
||||
|
||||
/// <summary>The ISO 20022 bank transaction code.</summary>
|
||||
/// <summary>Gets or sets the name of the counterparty that receives <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public string? CreditorName { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the account of the counterparty that receives <see cref="Transaction.TransactionAmount"/> during the transaction.</summary>
|
||||
public TransactionAccount? CreditorAccount { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the ISO 20022 bank transaction code.</summary>
|
||||
/// <example>Some example values:
|
||||
/// <code>
|
||||
/// PMNT-ICDT-STDO
|
||||
/// PMNT-IRCT-STDO
|
||||
/// </code></example>
|
||||
public string? BankTransactionCode { get; init; }
|
||||
public string? BankTransactionCode { get; set; }
|
||||
|
||||
/// <summary>A transaction id, used both by the transaction and any fees paid to the <see cref="Institution"/> for the transaction.</summary>
|
||||
public string? EntryReference { get; init; }
|
||||
/// <summary>Gets or sets a transaction id, used both by the transaction and any fees paid to the <see cref="Institution"/> for the transaction.</summary>
|
||||
public string? EntryReference { get; set; }
|
||||
|
||||
/// <summary>Additional structured information about the transaction from the institution.</summary>
|
||||
/// <summary>Gets or sets additional structured information about the transaction from the institution.</summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// PURCHASE
|
||||
/// INWARD TRANSFER
|
||||
/// </code></example>
|
||||
public string? AdditionalInformation { get; init; }
|
||||
public string? AdditionalInformation { get; set; }
|
||||
}
|
||||
|
||||
@@ -5,7 +5,4 @@
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>A transaction that is still pending.</summary>
|
||||
/// <param name="TransactionAmount">The amount transferred in this transaction.</param>
|
||||
/// <param name="UnstructuredInformation">Unstructured information about the transaction, usually added by the debtor.</param>
|
||||
public record PendingTransaction(AmountInCurrency TransactionAmount, string UnstructuredInformation)
|
||||
: Transaction(TransactionAmount, UnstructuredInformation);
|
||||
public record PendingTransaction : Transaction;
|
||||
|
||||
@@ -6,17 +6,18 @@ using System.Text.Json.Serialization;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
#pragma warning disable SA1623
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>Common information for all transactions.</summary>
|
||||
/// <param name="TransactionAmount">The amount transferred in this transaction.</param>
|
||||
/// <param name="UnstructuredInformation">Unstructured information about the transaction, usually added by the debtor.</param>
|
||||
public abstract record Transaction(
|
||||
AmountInCurrency TransactionAmount,
|
||||
[property: JsonPropertyName("remittanceInformationUnstructured")] string UnstructuredInformation)
|
||||
public abstract record Transaction
|
||||
{
|
||||
/// <summary>The date when the transaction was valued at.</summary>
|
||||
public LocalDate? ValueDate { get; init; }
|
||||
/// <summary>Gets or sets the amount transferred in this transaction.</summary>
|
||||
public AmountInCurrency TransactionAmount { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets unstructured information about the transaction, usually added by the debtor.</summary>
|
||||
[JsonPropertyName("remittanceInformationUnstructured")]
|
||||
public string UnstructuredInformation { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the date when the transaction was valued at.</summary>
|
||||
public LocalDate? ValueDate { get; set; }
|
||||
}
|
||||
|
||||
@@ -5,5 +5,8 @@
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>An account that can be referenced from a <see cref="Transaction"/>.</summary>
|
||||
/// <param name="Iban">The IBAN of the account.</param>
|
||||
public record TransactionAccount(string Iban);
|
||||
public record TransactionAccount
|
||||
{
|
||||
/// <summary>Gets or sets the IBAN of the account.</summary>
|
||||
public string Iban { get; set; } = null!;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,16 @@ using System.Collections.Generic;
|
||||
namespace VMelnalksnis.NordigenDotNet.Accounts;
|
||||
|
||||
/// <summary>All transactions of an account.</summary>
|
||||
/// <param name="Booked">All transactions that have been booked.</param>
|
||||
/// <param name="Pending">All transaction that are still pending.</param>
|
||||
public record Transactions(List<BookedTransaction> Booked, List<PendingTransaction> Pending);
|
||||
public record Transactions
|
||||
{
|
||||
/// <summary>Gets or sets all transactions that have been booked.</summary>
|
||||
public List<BookedTransaction> Booked { get; set; } = null!;
|
||||
|
||||
internal record TransactionsWrapper(Transactions Transactions);
|
||||
/// <summary>Gets or sets all transaction that are still pending.</summary>
|
||||
public List<PendingTransaction> Pending { get; set; } = null!;
|
||||
}
|
||||
|
||||
internal class TransactionsWrapper
|
||||
{
|
||||
public Transactions Transactions { get; set; } = null!;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -12,54 +15,56 @@ namespace VMelnalksnis.NordigenDotNet.Agreements;
|
||||
/// <inheritdoc />
|
||||
public sealed class AgreementClient : IAgreementClient
|
||||
{
|
||||
private readonly NordigenHttpClient _nordigenHttpClient;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly NordigenSerializationContext _context;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="AgreementClient"/> class.</summary>
|
||||
/// <param name="nordigenHttpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
public AgreementClient(NordigenHttpClient nordigenHttpClient)
|
||||
/// <param name="httpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
/// <param name="serializerOptions">Nordigen specific instance of <see cref="JsonSerializerOptions"/>.</param>
|
||||
public AgreementClient(HttpClient httpClient, NordigenJsonSerializerOptions serializerOptions)
|
||||
{
|
||||
_nordigenHttpClient = nordigenHttpClient;
|
||||
_httpClient = httpClient;
|
||||
_context = serializerOptions.Context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IAsyncEnumerable<EndUserAgreement> Get(int pageSize = 100, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _nordigenHttpClient.GetPaginated<EndUserAgreement>(Routes.Agreements.PaginatedUri(100), cancellationToken);
|
||||
return _httpClient.GetPaginated(
|
||||
Routes.Agreements.PaginatedUri(pageSize),
|
||||
_context.PaginatedListEndUserAgreement,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<EndUserAgreement> Get(Guid id, CancellationToken cancellationToken = default)
|
||||
public Task<EndUserAgreement> Get(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var agreement = await _nordigenHttpClient
|
||||
.Get<EndUserAgreement>(Routes.Agreements.IdUri(id), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return agreement!;
|
||||
return _httpClient.GetFromJsonAsync(Routes.Agreements.IdUri(id), _context.EndUserAgreement, cancellationToken)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<EndUserAgreement> Post(EndUserAgreementCreation agreementCreation)
|
||||
public Task<EndUserAgreement> Post(EndUserAgreementCreation agreementCreation)
|
||||
{
|
||||
var agreement = await _nordigenHttpClient
|
||||
.Post<EndUserAgreementCreation, EndUserAgreement>(Routes.Agreements.Uri, agreementCreation)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return agreement!;
|
||||
return _httpClient.Post(
|
||||
Routes.Agreements.Uri,
|
||||
agreementCreation,
|
||||
_context.EndUserAgreementCreation,
|
||||
_context.EndUserAgreement)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Delete(Guid id)
|
||||
public Task Delete(Guid id)
|
||||
{
|
||||
await _nordigenHttpClient.Delete(Routes.Agreements.IdUri(id)).ConfigureAwait(false);
|
||||
return _httpClient.Delete(Routes.Agreements.IdUri(id));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<EndUserAgreement> Put(Guid id, EndUserAgreementAcceptance acceptance)
|
||||
public Task<EndUserAgreement> Put(Guid id, EndUserAgreementAcceptance acceptance)
|
||||
{
|
||||
var agreement = await _nordigenHttpClient
|
||||
.Put<EndUserAgreementAcceptance, EndUserAgreement>(Routes.Agreements.AcceptUri(id), acceptance)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return agreement!;
|
||||
return _httpClient.Put(
|
||||
Routes.Agreements.AcceptUri(id),
|
||||
acceptance,
|
||||
_context.EndUserAgreementAcceptance,
|
||||
_context.EndUserAgreement)!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,25 +10,33 @@ using NodaTime;
|
||||
|
||||
using VMelnalksnis.NordigenDotNet.Institutions;
|
||||
|
||||
#pragma warning disable SA1623
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Agreements;
|
||||
|
||||
/// <summary>Details the end-user has agreement to share from a specific institution.</summary>
|
||||
/// <param name="Id">The id of the end-user agreement.</param>
|
||||
/// <param name="Created">The point in time when the agreement was created.</param>
|
||||
/// <param name="MaxHistoricalDays">Maximum number of days of transaction data to retrieve.</param>
|
||||
/// <param name="AccessValidForDays">Number of days from acceptance that the access can be used.</param>
|
||||
/// <param name="AccessScope">Level of information to access.</param>
|
||||
/// <param name="InstitutionId">An <see cref="Institution"/> ID for the agreement.</param>
|
||||
public record EndUserAgreement(
|
||||
Guid Id,
|
||||
Instant Created,
|
||||
[property: JsonPropertyName("max_historical_days")] int MaxHistoricalDays,
|
||||
[property: JsonPropertyName("access_valid_for_days")] int AccessValidForDays,
|
||||
[property: JsonPropertyName("access_scope")] List<string> AccessScope,
|
||||
[property: JsonPropertyName("institution_id")] string InstitutionId)
|
||||
public record EndUserAgreement
|
||||
{
|
||||
/// <summary>The point int time when the end user accepted the agreement.</summary>
|
||||
public Instant? Accepted { get; init; }
|
||||
/// <summary>Gets or sets the id of the end-user agreement.</summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the point in time when the agreement was created.</summary>
|
||||
public Instant Created { get; set; }
|
||||
|
||||
/// <summary>Gets or sets maximum number of days of transaction data to retrieve.</summary>
|
||||
[JsonPropertyName("max_historical_days")]
|
||||
public int MaxHistoricalDays { get; set; }
|
||||
|
||||
/// <summary>Gets or sets number of days from acceptance that the access can be used.</summary>
|
||||
[JsonPropertyName("access_valid_for_days")]
|
||||
public int AccessValidForDays { get; set; }
|
||||
|
||||
/// <summary>Gets or sets level of information to access.</summary>
|
||||
[JsonPropertyName("access_scope")]
|
||||
public List<string> AccessScope { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets an <see cref="Institution"/> ID for the agreement.</summary>
|
||||
[JsonPropertyName("institution_id")]
|
||||
public string InstitutionId { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the point int time when the end user accepted the agreement.</summary>
|
||||
public Instant? Accepted { get; set; }
|
||||
}
|
||||
|
||||
@@ -7,8 +7,13 @@ using System.Text.Json.Serialization;
|
||||
namespace VMelnalksnis.NordigenDotNet.Agreements;
|
||||
|
||||
/// <summary>Details needed to accept an end-user agreement.</summary>
|
||||
/// <param name="UserAgent">User agent string for the end user.</param>
|
||||
/// <param name="IpAddress">End user IP address.</param>
|
||||
public record EndUserAgreementAcceptance(
|
||||
[property: JsonPropertyName("user_agent")] string UserAgent,
|
||||
[property: JsonPropertyName("ip_address")] string IpAddress);
|
||||
public record EndUserAgreementAcceptance(string UserAgent, string IpAddress)
|
||||
{
|
||||
/// <summary>Gets user agent string for the end user.</summary>
|
||||
[JsonPropertyName("user_agent")]
|
||||
public string UserAgent { get; } = UserAgent;
|
||||
|
||||
/// <summary>Gets end user IP address.</summary>
|
||||
[JsonPropertyName("ip_address")]
|
||||
public string IpAddress { get; } = IpAddress;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ using System.Text.Json.Serialization;
|
||||
|
||||
using VMelnalksnis.NordigenDotNet.Institutions;
|
||||
|
||||
#pragma warning disable SA1623
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Agreements;
|
||||
|
||||
/// <summary>Details needed to create a new end-user agreement.</summary>
|
||||
@@ -38,19 +36,19 @@ public record EndUserAgreementCreation
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>An <see cref="Institution"/> id for this agreement.</summary>
|
||||
/// <summary>Gets an <see cref="Institution"/> id for this agreement.</summary>
|
||||
[JsonPropertyName("institution_id")]
|
||||
public string InstitutionId { get; }
|
||||
|
||||
/// <summary>Maximum number of days of transaction data to retrieve.</summary>
|
||||
/// <summary>Gets maximum number of days of transaction data to retrieve.</summary>
|
||||
[JsonPropertyName("max_historical_days")]
|
||||
public int MaxHistoricalDays { get; }
|
||||
|
||||
/// <summary>Number of days from acceptance that the access can be used.</summary>
|
||||
/// <summary>Gets number of days from acceptance that the access can be used.</summary>
|
||||
[JsonPropertyName("access_valid_for_days")]
|
||||
public int AccessValidForDays { get; }
|
||||
|
||||
/// <summary>Level of information to access.</summary>
|
||||
/// <summary>Gets level of information to access.</summary>
|
||||
[JsonPropertyName("access_scope")]
|
||||
public List<string> AccessScope { get; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 Valters Melnalksnis
|
||||
// Licensed under the Apache License 2.0.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet;
|
||||
|
||||
internal static class HttpClientExtensions
|
||||
{
|
||||
internal static async IAsyncEnumerable<TResult> GetPaginated<TResult>(
|
||||
this HttpClient httpClient,
|
||||
string requestUri,
|
||||
JsonTypeInfo<PaginatedList<TResult>> typeInfo,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
where TResult : class
|
||||
{
|
||||
var next = requestUri;
|
||||
while (next is not null && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var paginatedList = await httpClient.GetFromJsonAsync(next, typeInfo, cancellationToken).ConfigureAwait(false);
|
||||
if (paginatedList?.Results is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var result in paginatedList.Results)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
|
||||
next = paginatedList.Next?.PathAndQuery;
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<TResult?> Post<TRequest, TResult>(
|
||||
this HttpClient httpClient,
|
||||
string requestUri,
|
||||
TRequest request,
|
||||
JsonTypeInfo<TRequest> requestTypeInfo,
|
||||
JsonTypeInfo<TResult> resultTypeInfo)
|
||||
{
|
||||
var response = await httpClient.PostAsJsonAsync(requestUri, request, requestTypeInfo).ConfigureAwait(false);
|
||||
await response.ThrowIfNotSuccessful().ConfigureAwait(false);
|
||||
return await response.Content.ReadFromJsonAsync(resultTypeInfo).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<TResult?> Put<TRequest, TResult>(
|
||||
this HttpClient httpClient,
|
||||
string requestUri,
|
||||
TRequest request,
|
||||
JsonTypeInfo<TRequest> requestTypeInfo,
|
||||
JsonTypeInfo<TResult> resultTypeInfo)
|
||||
{
|
||||
var response = await httpClient.PutAsJsonAsync(requestUri, request, requestTypeInfo).ConfigureAwait(false);
|
||||
await response.ThrowIfNotSuccessful().ConfigureAwait(false);
|
||||
return await response.Content.ReadFromJsonAsync(resultTypeInfo).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task Delete(this HttpClient httpClient, string requestUri)
|
||||
{
|
||||
var response = await httpClient.DeleteAsync(requestUri).ConfigureAwait(false);
|
||||
await response.ThrowIfNotSuccessful().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -9,16 +9,24 @@ using System.Text.Json.Serialization;
|
||||
namespace VMelnalksnis.NordigenDotNet.Institutions;
|
||||
|
||||
/// <summary>Account servicing payment service provider details.</summary>
|
||||
/// <param name="Id">The id of the service provider.</param>
|
||||
/// <param name="Name">The name of the service provider.</param>
|
||||
/// <param name="Bic">The BIC of the service provider.</param>
|
||||
/// <param name="TransactionTotalDays">The maximum number of days in the past the service provider will return transactions for.</param>
|
||||
/// <param name="Countries">All the countries supported by the service provider.</param>
|
||||
/// <param name="Logo">URI to the service provider's logo.</param>
|
||||
public record Institution(
|
||||
string Id,
|
||||
string Name,
|
||||
string Bic,
|
||||
[property: JsonPropertyName("transaction_total_days")] int TransactionTotalDays,
|
||||
List<string> Countries,
|
||||
Uri Logo);
|
||||
public record Institution
|
||||
{
|
||||
/// <summary>Gets or sets the id of the service provider.</summary>
|
||||
public string Id { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the name of the service provider.</summary>
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the BIC of the service provider.</summary>
|
||||
public string Bic { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the maximum number of days in the past the service provider will return transactions for.</summary>
|
||||
[JsonPropertyName("transaction_total_days")]
|
||||
public int TransactionTotalDays { get; set; }
|
||||
|
||||
/// <summary>Gets or sets all the countries supported by the service provider.</summary>
|
||||
public List<string> Countries { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets uRI to the service provider's logo.</summary>
|
||||
public Uri Logo { get; set; } = null!;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -11,32 +14,33 @@ namespace VMelnalksnis.NordigenDotNet.Institutions;
|
||||
/// <inheritdoc />
|
||||
public sealed class InstitutionClient : IInstitutionClient
|
||||
{
|
||||
private readonly NordigenHttpClient _nordigenHttpClient;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly NordigenSerializationContext _context;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="InstitutionClient"/> class.</summary>
|
||||
/// <param name="nordigenHttpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
public InstitutionClient(NordigenHttpClient nordigenHttpClient)
|
||||
/// <param name="httpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
/// <param name="serializerOptions">Nordigen specific instance of <see cref="JsonSerializerOptions"/>.</param>
|
||||
public InstitutionClient(HttpClient httpClient, NordigenJsonSerializerOptions serializerOptions)
|
||||
{
|
||||
_nordigenHttpClient = nordigenHttpClient;
|
||||
_httpClient = httpClient;
|
||||
_context = serializerOptions.Context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<Institution>> GetByCountry(string countryCode, CancellationToken cancellationToken = default)
|
||||
public Task<List<Institution>> GetByCountry(string countryCode, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var institutions = await _nordigenHttpClient
|
||||
.Get<List<Institution>>(Routes.Institutions.CountryUri(countryCode), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return institutions!;
|
||||
return _httpClient.GetFromJsonAsync(
|
||||
Routes.Institutions.CountryUri(countryCode),
|
||||
_context.ListInstitution,
|
||||
cancellationToken)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Institution> Get(string id, CancellationToken cancellationToken = default)
|
||||
public Task<Institution> Get(string id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var institution = await _nordigenHttpClient
|
||||
.Get<Institution>(Routes.Institutions.IdUri(id), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return institution!;
|
||||
return _httpClient.GetFromJsonAsync(
|
||||
Routes.Institutions.IdUri(id),
|
||||
_context.Institution,
|
||||
cancellationToken)!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2022 Valters Melnalksnis
|
||||
// Licensed under the Apache License 2.0.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet;
|
||||
|
||||
/// <summary><see cref="HttpClient"/> wrapper that uses the correct serialization settings for all requests.</summary>
|
||||
public sealed class NordigenHttpClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly JsonSerializerOptions _serializerOptions;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="NordigenHttpClient"/> class.</summary>
|
||||
/// <param name="httpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
/// <param name="nordigenJsonSerializerOptions">Nordigen specific instance of <see cref="JsonSerializerOptions"/>.</param>
|
||||
public NordigenHttpClient(HttpClient httpClient, NordigenJsonSerializerOptions nordigenJsonSerializerOptions)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_serializerOptions = nordigenJsonSerializerOptions.Options;
|
||||
}
|
||||
|
||||
internal async Task<TResult?> Get<TResult>(string requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _httpClient.GetFromJsonAsync<TResult>(requestUri, _serializerOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async IAsyncEnumerable<TResult> GetPaginated<TResult>(
|
||||
string requestUri,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
where TResult : class
|
||||
{
|
||||
var next = requestUri;
|
||||
while (next is not null && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var paginatedList = await Get<PaginatedList<TResult>>(next, cancellationToken).ConfigureAwait(false);
|
||||
if (paginatedList?.Results is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var result in paginatedList.Results)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
|
||||
next = paginatedList.Next?.PathAndQuery;
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<TResult?> Post<TRequest, TResult>(string requestUri, TRequest request)
|
||||
{
|
||||
var response = await _httpClient.PostAsJsonAsync(requestUri, request, _serializerOptions).ConfigureAwait(false);
|
||||
await response.ThrowIfNotSuccessful().ConfigureAwait(false);
|
||||
return await response.Content.ReadFromJsonAsync<TResult>(_serializerOptions).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task<TResult?> Put<TRequest, TResult>(string requestUri, TRequest request)
|
||||
{
|
||||
var response = await _httpClient.PutAsJsonAsync(requestUri, request, _serializerOptions).ConfigureAwait(false);
|
||||
await response.ThrowIfNotSuccessful().ConfigureAwait(false);
|
||||
return await response.Content.ReadFromJsonAsync<TResult>(_serializerOptions).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task Delete(string requestUri)
|
||||
{
|
||||
var response = await _httpClient.DeleteAsync(requestUri).ConfigureAwait(false);
|
||||
await response.ThrowIfNotSuccessful().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -10,18 +10,20 @@ using NodaTime.Serialization.SystemTextJson;
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet;
|
||||
|
||||
/// <summary><see cref="JsonSerializerOptions"/> for <see cref="NordigenHttpClient"/>.</summary>
|
||||
/// <summary><see cref="JsonSerializerOptions"/> for <see cref="INordigenClient"/>.</summary>
|
||||
public sealed class NordigenJsonSerializerOptions
|
||||
{
|
||||
/// <summary>Initializes a new instance of the <see cref="NordigenJsonSerializerOptions"/> class.</summary>
|
||||
/// <param name="dateTimeZoneProvider">Time zone provider for date and time serialization.</param>
|
||||
public NordigenJsonSerializerOptions(IDateTimeZoneProvider dateTimeZoneProvider)
|
||||
{
|
||||
Options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
|
||||
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
|
||||
{
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
}.ConfigureForNodaTime(dateTimeZoneProvider);
|
||||
|
||||
Context = new(options);
|
||||
}
|
||||
|
||||
internal JsonSerializerOptions Options { get; }
|
||||
internal NordigenSerializationContext Context { get; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2022 Valters Melnalksnis
|
||||
// Licensed under the Apache License 2.0.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using VMelnalksnis.NordigenDotNet.Accounts;
|
||||
using VMelnalksnis.NordigenDotNet.Agreements;
|
||||
using VMelnalksnis.NordigenDotNet.Institutions;
|
||||
using VMelnalksnis.NordigenDotNet.Requisitions;
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet;
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata, IgnoreReadOnlyProperties = true)]
|
||||
[JsonSerializable(typeof(Account))]
|
||||
[JsonSerializable(typeof(AccountDetailsWrapper))]
|
||||
[JsonSerializable(typeof(BalancesWrapper))]
|
||||
[JsonSerializable(typeof(TransactionsWrapper))]
|
||||
[JsonSerializable(typeof(EndUserAgreement))]
|
||||
[JsonSerializable(typeof(PaginatedList<EndUserAgreement>))]
|
||||
[JsonSerializable(typeof(EndUserAgreementAcceptance))]
|
||||
[JsonSerializable(typeof(EndUserAgreementCreation))]
|
||||
[JsonSerializable(typeof(Institution))]
|
||||
[JsonSerializable(typeof(List<Institution>))]
|
||||
[JsonSerializable(typeof(Requisition))]
|
||||
[JsonSerializable(typeof(PaginatedList<Requisition>))]
|
||||
[JsonSerializable(typeof(RequisitionCreation))]
|
||||
internal partial class NordigenSerializationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -7,5 +7,14 @@ using System.Collections.Generic;
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet;
|
||||
|
||||
internal sealed record PaginatedList<TResult>(int? Count, Uri? Next, Uri? Previous, List<TResult>? Results)
|
||||
where TResult : class;
|
||||
internal sealed class PaginatedList<TResult>
|
||||
where TResult : class
|
||||
{
|
||||
public int? Count { get; set; }
|
||||
|
||||
public Uri? Next { get; set; }
|
||||
|
||||
public Uri? Previous { get; set; }
|
||||
|
||||
public List<TResult>? Results { get; set; }
|
||||
}
|
||||
|
||||
@@ -8,45 +8,56 @@ using System.Text.Json.Serialization;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
#pragma warning disable SA1623
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Requisitions;
|
||||
|
||||
/// <summary>A request to access a user's account details from a single institution.</summary>
|
||||
/// <param name="Id">The id of the requisition.</param>
|
||||
/// <param name="Created">The point in time when the requisition was created.</param>
|
||||
/// <param name="Redirect">The URI to which the user will be redirected after authorizing access.</param>
|
||||
/// <param name="Status">The status of the requisition.</param>
|
||||
/// <param name="InstitutionId">The ID of the institution for which this requisition was made for.</param>
|
||||
/// <param name="Reference">Client specified reference for this requisition.</param>
|
||||
/// <param name="Accounts">Accounts retrieved within the scope of this requisition.</param>
|
||||
/// <param name="Link">URI to initiate the authorization with the institution.</param>
|
||||
/// <param name="AccountSelection">Whether to enable account selection view for the end user (if the institution supports it).</param>
|
||||
/// <param name="RedirectImmediate">Whether to enable redirect back to the client after account list is received.</param>
|
||||
public record Requisition(
|
||||
Guid Id,
|
||||
Instant Created,
|
||||
Uri Redirect,
|
||||
RequisitionStatus Status,
|
||||
[property: JsonPropertyName("institution_id")] string InstitutionId,
|
||||
string Reference,
|
||||
List<Guid> Accounts,
|
||||
Uri Link,
|
||||
[property: JsonPropertyName("account_selection")] bool AccountSelection,
|
||||
[property: JsonPropertyName("redirect_immediate")] bool RedirectImmediate)
|
||||
public record Requisition
|
||||
{
|
||||
/// <summary>The raw value of <see cref="Agreement"/>.</summary>
|
||||
[JsonPropertyName("agreement")]
|
||||
public string? AgreementValue { get; init; }
|
||||
/// <summary>Gets or sets the id of the requisition.</summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>The end-user-agreement of this requisition.</summary>
|
||||
/// <summary>Gets or sets the point in time when the requisition was created.</summary>
|
||||
public Instant Created { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the URI to which the user will be redirected after authorizing access.</summary>
|
||||
public Uri Redirect { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets the status of the requisition.</summary>
|
||||
public RequisitionStatus Status { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the ID of the institution for which this requisition was made for.</summary>
|
||||
[JsonPropertyName("institution_id")]
|
||||
public string InstitutionId { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets client specified reference for this requisition.</summary>
|
||||
public string Reference { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets accounts retrieved within the scope of this requisition.</summary>
|
||||
public List<Guid> Accounts { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets uRI to initiate the authorization with the institution.</summary>
|
||||
public Uri Link { get; set; } = null!;
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether whether to enable account selection view for the end user (if the institution supports it).</summary>
|
||||
[JsonPropertyName("account_selection")]
|
||||
public bool AccountSelection { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether whether to enable redirect back to the client after account list is received.</summary>
|
||||
[JsonPropertyName("redirect_immediate")]
|
||||
public bool RedirectImmediate { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the raw value of <see cref="Agreement"/>.</summary>
|
||||
[JsonPropertyName("agreement")]
|
||||
public string? AgreementValue { get; set; }
|
||||
|
||||
/// <summary>Gets the end-user-agreement of this requisition.</summary>
|
||||
[JsonIgnore]
|
||||
public Guid? Agreement => string.IsNullOrWhiteSpace(AgreementValue) ? null : Guid.Parse(AgreementValue);
|
||||
|
||||
/// <summary>A two-letter country code (ISO 639-1).</summary>
|
||||
/// <summary>Gets or sets a two-letter country code (ISO 639-1).</summary>
|
||||
[JsonPropertyName("user_language")]
|
||||
public string? UserLanguage { get; init; }
|
||||
public string? UserLanguage { get; set; }
|
||||
|
||||
/// <summary>Social security number for account ownership verification.</summary>
|
||||
public string? Ssn { get; init; }
|
||||
/// <summary>Gets or sets social security number for account ownership verification.</summary>
|
||||
public string? Ssn { get; set; }
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -12,44 +15,49 @@ namespace VMelnalksnis.NordigenDotNet.Requisitions;
|
||||
/// <inheritdoc />
|
||||
public sealed class RequisitionClient : IRequisitionClient
|
||||
{
|
||||
private readonly NordigenHttpClient _nordigenHttpClient;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly NordigenSerializationContext _context;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="RequisitionClient"/> class.</summary>
|
||||
/// <param name="nordigenHttpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
public RequisitionClient(NordigenHttpClient nordigenHttpClient)
|
||||
/// <param name="httpClient">Http client configured for making requests to the Nordigen API.</param>
|
||||
/// <param name="serializerOptions">Nordigen specific instance of <see cref="JsonSerializerOptions"/>.</param>
|
||||
public RequisitionClient(HttpClient httpClient, NordigenJsonSerializerOptions serializerOptions)
|
||||
{
|
||||
_nordigenHttpClient = nordigenHttpClient;
|
||||
_httpClient = httpClient;
|
||||
_context = serializerOptions.Context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IAsyncEnumerable<Requisition> Get(int pageSize = 100, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _nordigenHttpClient.GetPaginated<Requisition>(Routes.Requisitions.PaginatedUri(pageSize), cancellationToken);
|
||||
return _httpClient.GetPaginated(
|
||||
Routes.Requisitions.PaginatedUri(pageSize),
|
||||
_context.PaginatedListRequisition,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Requisition> Get(Guid id, CancellationToken cancellationToken = default)
|
||||
public Task<Requisition> Get(Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var requisition = await _nordigenHttpClient
|
||||
.Get<Requisition>(Routes.Requisitions.IdUri(id), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return requisition!;
|
||||
return _httpClient.GetFromJsonAsync(
|
||||
Routes.Requisitions.IdUri(id),
|
||||
_context.Requisition,
|
||||
cancellationToken)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Requisition> Post(RequisitionCreation requisitionCreation)
|
||||
public Task<Requisition> Post(RequisitionCreation requisitionCreation)
|
||||
{
|
||||
var requisition = await _nordigenHttpClient
|
||||
.Post<RequisitionCreation, Requisition>(Routes.Requisitions.Uri, requisitionCreation)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return requisition!;
|
||||
return _httpClient.Post(
|
||||
Routes.Requisitions.Uri,
|
||||
requisitionCreation,
|
||||
_context.RequisitionCreation,
|
||||
_context.Requisition)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Delete(Guid id)
|
||||
{
|
||||
await _nordigenHttpClient.Delete(Routes.Requisitions.IdUri(id)).ConfigureAwait(false);
|
||||
await _httpClient.Delete(Routes.Requisitions.IdUri(id)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,43 +7,46 @@ using System.Text.Json.Serialization;
|
||||
|
||||
using VMelnalksnis.NordigenDotNet.Institutions;
|
||||
|
||||
#pragma warning disable SA1623
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Requisitions;
|
||||
|
||||
/// <summary>Information needed to create a new <see cref="Requisition"/>.</summary>
|
||||
/// <param name="Redirect">Redirect URL to your application after end-user authorization with ASPSP.</param>
|
||||
/// <param name="InstitutionId">The id of the <see cref="Institution"/> for which to create a requisition for.</param>
|
||||
public record RequisitionCreation(Uri Redirect, [property: JsonPropertyName("institution_id")] string InstitutionId)
|
||||
public record RequisitionCreation(Uri Redirect, string InstitutionId)
|
||||
{
|
||||
/// <summary>The end-user-agreement of this requisition.</summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public Guid? Agreement { get; init; }
|
||||
/// <summary>Gets redirect URL to your application after end-user authorization with ASPSP.</summary>
|
||||
public Uri Redirect { get; } = Redirect;
|
||||
|
||||
/// <summary>A unique ID for internal referencing.</summary>
|
||||
/// <summary>Gets the id of the <see cref="Institution"/> for which to create a requisition for.</summary>
|
||||
[JsonPropertyName("institution_id")]
|
||||
public string InstitutionId { get; } = InstitutionId;
|
||||
|
||||
/// <summary>Gets or sets the end-user-agreement of this requisition.</summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? Reference { get; init; }
|
||||
public Guid? Agreement { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a unique ID for internal referencing.</summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? Reference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The language for all end users steps hosted by Nordigen in ISO 639-1 format.
|
||||
/// Gets or sets the language for all end users steps hosted by Nordigen in ISO 639-1 format.
|
||||
/// If not defined, the language set in the browser will be used instead.
|
||||
/// </summary>
|
||||
/// <seealso href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes"/>
|
||||
[JsonPropertyName("user_language")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? UserLanguage { get; init; }
|
||||
public string? UserLanguage { get; set; }
|
||||
|
||||
/// <summary>Optional SSN field to verify ownership of the account.</summary>
|
||||
/// <summary>Gets or sets optional SSN field to verify ownership of the account.</summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string? Ssn { get; init; }
|
||||
public string? Ssn { get; set; }
|
||||
|
||||
/// <summary>Option to enable account selection view for the end user.</summary>
|
||||
/// <summary>Gets or sets option to enable account selection view for the end user.</summary>
|
||||
[JsonPropertyName("account_selection")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public bool? AccountSelection { get; init; }
|
||||
public bool? AccountSelection { get; set; }
|
||||
|
||||
/// <summary>Enable redirect back to the client after account list received.</summary>
|
||||
/// <summary>Gets or sets enable redirect back to the client after account list received.</summary>
|
||||
[JsonPropertyName("redirect_immediate")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public bool? RedirectImmediate { get; init; }
|
||||
public bool? RedirectImmediate { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using NodaTime;
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Tokens;
|
||||
|
||||
/// <summary>Caches refresh and access tokens for <see cref="NordigenHttpClient"/>.</summary>
|
||||
/// <summary>Caches refresh and access tokens for <see cref="INordigenClient"/>.</summary>
|
||||
public sealed class NordigenTokenCache
|
||||
{
|
||||
private readonly NordigenOptions _nordigenOptions;
|
||||
|
||||
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace VMelnalksnis.NordigenDotNet.Tokens;
|
||||
|
||||
/// <summary>Handles authorization tokens for <see cref="NordigenHttpClient"/>.</summary>
|
||||
/// <summary>Handles authorization tokens for <see cref="INordigenClient"/>.</summary>
|
||||
public sealed class TokenDelegatingHandler : DelegatingHandler
|
||||
{
|
||||
private static readonly TokenSerializationContext _context = new(new(JsonSerializerDefaults.Web));
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright 2022 Valters Melnalksnis
|
||||
// Licensed under the Apache License 2.0.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace NodaTime;
|
||||
|
||||
[System.Obsolete("Proxy type for System.Text.Json to work around https://github.com/dotnet/runtime/issues/66679#issuecomment-1189027602")]
|
||||
internal readonly struct YearMonthDayCalendar
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user