A REST API built with ASP.NET Core (.NET 10) that processes financial transactions and returns real-time statistics over a 60-second rolling window.
The API accepts transaction records and computes aggregate statistics (count, sum, average, min, max) considering only transactions from the last 60 seconds. All data is stored in-memory — no database required.
| Technology | Version | Role |
|---|---|---|
| .NET / ASP.NET Core | 10.0 | Runtime & Web API framework |
| MediatR | 14.1.0 | CQRS pipeline |
| AutoMapper | 16.1.1 | DTO → Command mapping |
| Autofac | 9.1.0 | IoC container |
| FluentValidation | 12.1.1 | Input validation |
| Swashbuckle (Swagger) | 10.1.7 | API documentation |
| xUnit | 2.9.3 | Unit testing |
| Moq | 4.20.72 | Test mocking |
The project follows Clean Architecture with Domain-Driven Design (DDD) and CQRS via MediatR, organized into four layers:
RollingTransactionStats/
├── Domain/ # Entities, Value Objects, Domain Exceptions
├── Application/ # Commands, Queries, Handlers, Validators, DTOs
├── Infrastructure/ # In-memory repository, IoC module
└── Api/ # Controllers, Exception Handlers (Middleware)
Patterns in use:
- CQRS (Commands: create/delete; Queries: statistics)
- Value Objects (
Amount,Timestamp,TransactionId) with invariant enforcement - Repository Pattern (
ITransactionRepository) - MediatR Pipeline Behaviors (validation runs before every command handler)
- Three-tier Exception Handling (see Error Responses)
| Method | Route | Body | Success |
|---|---|---|---|
POST |
/transaction |
{ "amount": decimal, "timestamp": ISO8601 } |
201 Created |
DELETE |
/transaction |
— | 204 No Content |
GET |
/statistics |
— | 200 OK |
{
"amount": 12.50,
"timestamp": "2026-04-03T15:30:00Z"
}Validation rules:
amountmust be>= 0timestampcannot be in the future
Deletes all transactions from memory. Returns no body.
Returns aggregated statistics for all transactions within the last 60 seconds:
{
"count": 3,
"sum": 35.00,
"avg": 11.67,
"min": 5.00,
"max": 18.50
}If no transactions exist within the window, all values return
0.
All errors follow the RFC 7807 Problem Details format.
| Status | When |
|---|---|
422 Unprocessable Entity |
Input validation fails (e.g. negative amount, future timestamp) |
400 Bad Request |
Domain rule violation |
500 Internal Server Error |
Unhandled exception |
git clone https://github.com/ramon-bernardo/RollingTransactionStats.git
cd RollingTransactionStats
dotnet runThe API will be available at:
http://localhost:5182https://localhost:7251
Navigate to http://localhost:5182/swagger to explore and test the API interactively.
A ready-to-use collection is available at Postman/Collection.json. Import it into Postman to test all endpoints.
dotnet test Tests/RollingTransactionStats.Tests.csprojTest coverage includes:
- Domain — Value Object invariants (
Amount,Timestamp,Transaction) - Application — Command handlers, query handler (rolling window logic), validators
Benchmarks are implemented with BenchmarkDotNet and cover the two main hot paths:
| Benchmark | What it measures |
|---|---|
TransactionRepositoryBenchmarks |
Add, GetSince (60s window), DeleteAll |
StatisticsCalculationBenchmarks |
Full statistics calculation via GetStatisticsQueryHandler |
Each benchmark runs with TransactionCount of 10, 100, and 1_000 to observe scaling behavior.
Must be run in Release mode — BenchmarkDotNet requires it.
dotnet run --project Benchmarks/RollingTransactionStats.Benchmarks.csproj -c ReleaseResults are saved to Benchmarks/BenchmarkDotNet.Artifacts/ after each run.
This project is licensed under the MIT License — see the LICENSE file for details.