The goal of the test task is to develop a web API of a task planning system. The web API must allow to create and edit a task hierarchy, as well as perform calculations on the data fields of the tasks in the hierarchy.
ASP.NET Core 6, C#, EntityFramework Core, MS SQL Server Database, Docker
- VPSDemo.Api (main Web API project) contains Controllers (endpoints), Contracts, Mappers, Filters.
- VPSDemo.Application contains Interfaces, Errors, Logic to fetch data
- VPSDemo.Domain contains Entities
- VPSDemo.Infrastructure contains Repositories, Migration files and other fiels related to DB
Clean Architectue, Domain Driven Design, Repository Pattern
- Automapper is set in VPSDemo.Api.Mapper
- TaskMapperProfiles.cs to configure automapper for Task entity
- Instead of throwing and using exceptions we use a Return object.
- Return object has a Value, IsFailed, IsSuccess properties.
- errors of Return object are handled via ProblemHandler in BaseController.
- Globar errors are handled in VPSDemo.Api.Controllers ErrorsController.cs
- All other non server side errors are handled via ProblemHandler method in VPSDemo.Api.Controllers BaseController.cs
- Uri and query identifier parameter is validated via ValidateIdentifier method in VPSDemo.Api.Validations BaseValidation.cs
- UI Models (Contracts)are validated via validation filter defined in VPSDemo.Api.Filters ValidationFilterAttribute.cs
- All errors are serverd to the user with ProblemDetails class Problem Details Specification for HTTP APIs
- in order to add custom 'errorMessage' to ProblemDetails class we override method CreateProblemDetails in VPSDemo.Api.Common VPSProblemDetailsFactory.cs
- DB Model (Entity) defined in VPSDemo.Domain.Entities Task.cs class
- UI models (Contracts) defined in VPSDemo.Api.Contracts
- Create Task, Delete Task, Edit Task, Get Task, Assign Sub task
- Get Task - also retrieves sub Tasks
- Delete Task - Only a task which does not have sub-tasks can be deleted.
Request body | Response (SUCCESS 200 Ok) |
---|---|
{
"title": "MAIN TASK A",
"description": "description",
"effortEstimation": 1
} |
{
"identifier": 1,
"title": "MAIN TASK A",
"description": "description",
"effortEstimation": 1,
"aggregatedEffortEstimation": 281,
"status": "New",
"subTasks": [],
"creationDate": "2022-11-13T23:15:12"
} |
Request body | Response (FAIL 400) |
---|---|
{
"description": "description"
} |
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Validation Error",
"status": 400,
"traceId": "00-21790aa1386552307b4397420650fefa-18df5db6c8db92e1-00",
"errorMessage": [
"The Title field is required."
]
} |
Request body | Response (FAIL 400) |
---|---|
{
"description": "description"
} |
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Validation Error",
"status": 400,
"traceId": "00-21790aa1386552307b4397420650fefa-18df5db6c8db92e1-00",
"errorMessage": [
"The Status field is required.",
"The field Status is invalid"
]
} |
Query (Key: Value) | Response (Success 200 Ok) |
---|---|
parentIdentifier: 3 |
{
"identifier": 3,
"title": "TASK B",
"description": "description",
"effortEstimation": 0,
"aggregatedEffortEstimation": 80,
"status": "New",
"subTasks": [
{
"identifier": 4,
"title": "TASK C",
"description": "description",
"effortEstimation": 80,
"aggregatedEffortEstimation": 0,
"status": "New",
"subTasks": [],
"creationDate": "2022-11-13T23:17:44"
}
],
"creationDate": "2022-11-13T23:15:12"
} |
Response (Success 200 Ok) |
---|
{
"identifier": 3,
"title": "TASK B",
"description": "description",
"effortEstimation": 0,
"aggregatedEffortEstimation": 80,
"status": "New",
"subTasks": [
{
"identifier": 4,
"title": "TASK C",
"description": "description",
"effortEstimation": 80,
"aggregatedEffortEstimation": 0,
"status": "New",
"subTasks": [],
"creationDate": "2022-11-13T23:17:44"
}
],
"creationDate": "2022-11-13T23:15:12"
} |
Response (Success 204 NoContent) |
---|
Response (FAIL 409) |
---|
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
"title": "Conflict",
"status": 409,
"traceId": "00-7d2127bfe809238b8d944c0cb64fec29-d17390d3fe719a93-00",
"errorMessage": [
"Task with identifier [1] has assigned one or more Task with identifiers: [4]"
]
} |
VPSDemo.Api contains Dockerfile to build docker image.
We use base image mcr.microsoft.com/dotnet/sdk:6.0 to build binaries.
.Net runtime image mcr.microsoft.com/dotnet/aspnet:6.0 is used to serve artefacts we've created