Overview

The API layer in Clean.Net is designed to be lightweight and serves purely as an entry point to the application. This design follows Clean Architecture principles, ensuring:

  • Clear separation of concerns - API layer only handles HTTP requests/responses
  • Easy interface replacement - API layer can be swapped with minimal impact
  • Isolated business logic - All business rules reside in the Application layer
  • One-to-one mapping - Each endpoint corresponds to a single handler (CQRS pattern) in the appllication layer
Adding a New Endpoint

Example based on User management:

1. Controller Endpoint
// API Layer
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    private readonly IMediator _mediator;

    public UserController(IMediator mediator)
    {
        _mediator = mediator;
    }
    
    [HttpPost()]
    [Authorize(Policy = AuthorisationPolicyNames.RequireAdmin)]
    [ProducesResponseType(typeof(CreateUserResponse), 201)]
    [ProducesResponseType(typeof(ProblemDetails<CreateUserError>), 400)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> CreateUser(CreateUserRequest request, CancellationToken cancellationToken) => 
        await _mediator.SendWithErrorHandling<CreateUserResponse, CreateUserError>(request, cancellationToken);
}
3. Handler Implementation
// Application Layer
public class CreateUserHandler : IRequestHandler<CreateUserRequest, Result<CreateUserResponse>>
{
    private readonly IUserRepository _userRepository;
    private readonly IPasswordHasher<Domain.Entities.User> _passwordHasher;

    public CreateUserHandler(IUserRepository userRepository, IPasswordHasher<Domain.Entities.User> passwordHasher)
    {
        _userRepository = userRepository;
        _passwordHasher = passwordHasher;
    }

    public async Task<Result<CreateUserResponse>> Handle(CreateUserRequest request, CancellationToken cancellationToken)
    {
        var user = await _userRepository.Get(request.Id);

        if (user is null)
        {
            var hashedPassword = _passwordHasher.HashPassword(null!, request.Password);
            user = request.ToUser(hashedPassword);
            await _userRepository.Add(user);
        }

        return user.ToCreateUserResponse();
    }
}
All endpoints are made available on the Swagger UI page. Visit API Documentation page for more details