feat(api): add validation for connect account request

This commit is contained in:
Stevan Freeborn
2026-02-13 04:37:47 -06:00
parent e88adfd2a7
commit 683ca3fac4
4 changed files with 96 additions and 1 deletions
@@ -9,7 +9,9 @@ internal static class Endpoint
return groupBuilder.MapPost(Route, HandleAsync); return groupBuilder.MapPost(Route, HandleAsync);
} }
private static async Task<IResult> HandleAsync() private static async Task<IResult> HandleAsync(
[FromBody] Request request
)
{ {
return Results.Ok(); return Results.Ok();
} }
@@ -0,0 +1,22 @@
namespace FiscalOS.API.Accounts.Connect;
public record Request : IValidatableObject
{
public string PublicToken { get; init; } = string.Empty;
public string PlaidInstitutionId { get; init; } = string.Empty;
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(PublicToken))
{
var fieldName = nameof(PublicToken);
yield return new($"The {fieldName} field is required.", [fieldName]);
}
if (string.IsNullOrWhiteSpace(PlaidInstitutionId))
{
var fieldName = nameof(PlaidInstitutionId);
yield return new($"The {fieldName} field is required.", [fieldName]);
}
}
}
@@ -11,4 +11,73 @@ public class ConnectTests(TestApi testApi) : IntegrationTest(testApi)
await res.Should().BeProblemDetails(HttpStatusCode.Unauthorized); await res.Should().BeProblemDetails(HttpStatusCode.Unauthorized);
} }
[Fact]
public async Task Connect_WhenCalledWithoutPublicTokenOrPlaidInstitutionId_ItShouldReturn400WithProblemDetails()
{
var jwt = JwtTokenBuilder.New()
.WithClaim(JwtRegisteredClaimNames.Sub, Guid.NewGuid().ToString())
.Build();
using var content = new StringContent(JsonSerializer.Serialize(new { }), Encoding.UTF8, "application/json");
using var request = new HttpRequestMessage(HttpMethod.Post, ConnectUri)
{
Content = content,
};
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
var response = await Client.SendAsync(request, TestContext.Current.CancellationToken);
await response.Should().BeValidationProblemDetails(new Dictionary<string, string[]>()
{
["PublicToken"] = ["The PublicToken field is required."],
["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."],
});
}
[Fact]
public async Task Connect_WhenCalledWithoutPublicToken_ItShouldReturn400WithProblemDetails()
{
var jwt = JwtTokenBuilder.New()
.WithClaim(JwtRegisteredClaimNames.Sub, Guid.NewGuid().ToString())
.Build();
var json = JsonSerializer.Serialize(new { plaidInstitutionId = "id" });
using var content = new StringContent(json, Encoding.UTF8, "application/json");
using var request = new HttpRequestMessage(HttpMethod.Post, ConnectUri)
{
Content = content,
};
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
var response = await Client.SendAsync(request, TestContext.Current.CancellationToken);
await response.Should().BeValidationProblemDetails(new Dictionary<string, string[]>()
{
["PublicToken"] = ["The PublicToken field is required."],
});
}
[Fact]
public async Task Connect_WhenCalledWithoutPlaidInstitutionId_ItShouldReturn400WithProblemDetails()
{
var jwt = JwtTokenBuilder.New()
.WithClaim(JwtRegisteredClaimNames.Sub, Guid.NewGuid().ToString())
.Build();
var json = JsonSerializer.Serialize(new { publicToken = "token" });
using var content = new StringContent(json, Encoding.UTF8, "application/json");
using var request = new HttpRequestMessage(HttpMethod.Post, ConnectUri)
{
Content = content,
};
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
var response = await Client.SendAsync(request, TestContext.Current.CancellationToken);
await response.Should().BeValidationProblemDetails(new Dictionary<string, string[]>()
{
["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."],
});
}
} }
+2
View File
@@ -4,6 +4,8 @@ global using System.Net.Http.Headers;
global using System.Net.Http.Json; global using System.Net.Http.Json;
global using System.Security.Claims; global using System.Security.Claims;
global using System.Security.Cryptography; global using System.Security.Cryptography;
global using System.Text;
global using System.Text.Json;
global using AwesomeAssertions.Execution; global using AwesomeAssertions.Execution;
global using AwesomeAssertions.Primitives; global using AwesomeAssertions.Primitives;