96 lines
3.2 KiB
C#
96 lines
3.2 KiB
C#
using System.Net.Http.Json;
|
|
using System.Text.Json;
|
|
using Asentrafin.Api.Configuration;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace Asentrafin.Api.Services.Plaid;
|
|
|
|
public class PlaidClient(HttpClient httpClient, IOptions<PlaidOptions> options) : IPlaidClient
|
|
{
|
|
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
|
private readonly PlaidOptions _options = options.Value;
|
|
|
|
public Task<JsonDocument> AccountsGetAsync(string accessToken, CancellationToken cancellationToken)
|
|
{
|
|
return PostAsync("/accounts/get", BuildAuthedRequest(accessToken), cancellationToken);
|
|
}
|
|
|
|
public Task<JsonDocument> TransactionsSyncAsync(string accessToken, string? cursor, CancellationToken cancellationToken)
|
|
{
|
|
var body = BuildAuthedRequest(accessToken);
|
|
body["cursor"] = cursor;
|
|
body["count"] = 500;
|
|
body["options"] = new Dictionary<string, object?>
|
|
{
|
|
["include_original_description"] = true,
|
|
["personal_finance_category_version"] = "v2"
|
|
};
|
|
|
|
return PostAsync("/transactions/sync", body, cancellationToken);
|
|
}
|
|
|
|
public Task<JsonDocument> InvestmentsHoldingsGetAsync(string accessToken, CancellationToken cancellationToken)
|
|
{
|
|
return PostAsync("/investments/holdings/get", BuildAuthedRequest(accessToken), cancellationToken);
|
|
}
|
|
|
|
public Task<JsonDocument> InvestmentsTransactionsGetAsync(
|
|
string accessToken,
|
|
DateOnly startDate,
|
|
DateOnly endDate,
|
|
int count,
|
|
int offset,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var body = BuildAuthedRequest(accessToken);
|
|
body["start_date"] = startDate.ToString("yyyy-MM-dd");
|
|
body["end_date"] = endDate.ToString("yyyy-MM-dd");
|
|
body["options"] = new Dictionary<string, object?>
|
|
{
|
|
["count"] = count,
|
|
["offset"] = offset
|
|
};
|
|
|
|
return PostAsync("/investments/transactions/get", body, cancellationToken);
|
|
}
|
|
|
|
private async Task<JsonDocument> PostAsync(
|
|
string path,
|
|
Dictionary<string, object?> body,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
EnsureConfigured();
|
|
|
|
using var response = await httpClient.PostAsJsonAsync(path, body, JsonOptions, cancellationToken);
|
|
var responseBody = await response.Content.ReadAsStringAsync(cancellationToken);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
throw new HttpRequestException(
|
|
$"Plaid request to {path} failed with {(int)response.StatusCode}: {responseBody}",
|
|
null,
|
|
response.StatusCode);
|
|
}
|
|
|
|
return JsonDocument.Parse(responseBody);
|
|
}
|
|
|
|
private Dictionary<string, object?> BuildAuthedRequest(string accessToken)
|
|
{
|
|
return new Dictionary<string, object?>
|
|
{
|
|
["client_id"] = _options.ClientId,
|
|
["secret"] = _options.Secret,
|
|
["access_token"] = accessToken
|
|
};
|
|
}
|
|
|
|
private void EnsureConfigured()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(_options.ClientId) || string.IsNullOrWhiteSpace(_options.Secret))
|
|
{
|
|
throw new InvalidOperationException("Plaid ClientId and Secret must be configured.");
|
|
}
|
|
}
|
|
}
|