The application is a .NET 6.0 API developed following https://ipkiss.pragmazero.com/ requirements.
- The API is structured according to practices and principles such as Clean Code, Clean Architecture, DDD, TDD, and SOLID.
- It was developed following TBD (trunk based development) and PRs (pull requests) for every new code
merged to the main branch.
- The commits were not squashed before merging the feature branch to main.
- Following the Clean Architecture, the projects were divided in 4 layers: Domain, Application, Infrastructure and Web. Each one making reference to the next one.
- Unit testing was also created following the test-driven development. Using the dependency inversion enabled the use of mocks.
- The driven-domain design was another approach as well. The
/event
endpoint became a transaction within the application which can be a deposit, a withdraw or a transfer.- This approach relies on Single Responsibility from SOLID principles.
- The endpoint
/balance
was translated to operations with anAccount
domain model which owns a balance property. This model also had the operations to create withdraws and deposits within the domain.
- The Mediator design pattern was used to decouple and enable the communication between the Web layer and the
Application one.
- Because of the .NET framework and Mediatr library, it was possible to reassert the use of Dependency Injection.
- This approach also relies on Dependency Inversion from SOLID principles.
- Among the mediator behavior, its pipeline was used to attach a validator for each request created.
- Because of the .NET framework and Mediatr library, it was possible to reassert the use of Dependency Injection.
- The data is persisted to an in-memory database. Once the application is down, the data is lost.
- The mediator approach also ensured CQRS, distinguishing the requests between command or query.
- The CQRS approach was used with interfaces required from the Application layer which were implemented
by the Infrastructure layer. There was one interface for reading and another for writing operations.
- This approach also relies on Interface Segregation from SOLID principles.
The following section explains the flow of a deposit operation.
- Calling
POST /event {"type":"deposit", "destination":"100", "amount":10}
would reach the/event
endpoint in the Web layer. - Inside the controller, the request is translated to a
CreateTransactionCommand
handled by aCreateTransactionCommandHandler
in the Application layer. - The handler translates the deposit to a
CreateDepositCommand
that is handled by aCreateDepositCommandHandler
. - During the handling process, a validator for each request (command) is also done.
- The last handler consumes an
IAccountWriter
to do writing operations from the Infrastructure layer. - The deposit handler creates a
GetAccountQuery
to check if the account already exists. - If the account exists, the deposit amount is added to its balance from
IAccountWriter
. Otherwise, the account is created with a balance with deposit amount using aCreateAccountCommand
. - The response is returned as a deposit domain model.
You can run the API using either docker
or dotnet
.
Install docker, build the image using.
docker build . -t account-api
And run the application with.
docker run --network="host" -rm -p 80:80 -p 443:443 account-api
- The parameters ensure that the connection can be made through
http://localhost/swagger/index.html
. - It binds the HTTP and HTTPS ports and your localhost to the container localhost.
- The
-rm
parameter automatically remove the container when it exits.
Install .NET 6.0, clone this repository and run the following command from the root path.
dotnet run --project src/Web/
Accessing /swagger
will redirect you to the API documentation.
Use the following command from the root path to run tests.
dotnet test