Easiest way to build the fastest REST API in C# and .NET 7 using CQRS
Tags: dotnet, csharp, cqrs, fastarchitecture
Published: 2023-04-25 21:25:40

Sometime ago I stumbled upon this amazing library built by amazing people: https://fast-endpoints.com 

It was also featured on this platform https://dev.to/djnitehawk/building-rest-apis-in-net-6-the-easy-way-3h0d (written by the author). 

I gave it a go and I was impressed how easy and fast it was to set it all up. Since I'm not a big fan of [REPR](https://deviq.com/design-patterns/repr-design-pattern) pattern almost all my projects are using [CQRS ](https://martinfowler.com/bliki/CQRS.html) pattern with a help of MediatR ](https://github.com/jbogard/MediatR) I immediately started going over something similar that [Fast Endpoints](https://fast-endpoints.com ) offer which is a [command bus](https://fast-endpoints.com/docs/command-bus#_1-define-a-command). 

So I put the project together with certain goals:

1. Keep everything in command/query handlers 
2. Keep API as thin as possible
3. Execute handlers within Azure Functions (keeping them thin as well)
4. Make handlers easily unit testable

I put all this up on Github [FastArchitecture](https://github.com/kedzior-io/fast-architecture) :fire:

You can see it in action on a real-world project [Salarioo.com](https://salarioo.com) :fire:

The **API endpoint** ended up being a single line:

```csharp
public class GetOrdersEndpoint : ApiEndpoint<GetOrders.Query, GetOrders.Response>
{
    public override void Configure()
    {
        Get("orders/list");
        AllowAnonymous();
        ResponseCache(60);
    }

    public override async Task HandleAsync(GetOrders.Query query, CancellationToken ct) => await SendAsync(query, ct);
}
```

The **Query handler** in a self contained class that contains:
- Query definition (the input)
- Query response (the output)
- Handler (stuff that happens within execution)


```csharp
public static class GetOrders
{
    public sealed class Query : IQuery<IHandlerResponse<Response>>
    {
    }

    public sealed class Response
    {
        public IReadOnlyCollection<OrderListModel> Orders { get; private set; }

        public Response(IReadOnlyCollection<Domain.Order> orders)
        {
            Orders = orders.Select(OrderListModel.Create).ToList();
        }
    }

    public sealed class Handler : QueryHandler<Query, Response>
    {
        public Handler(IHandlerContext context) : base(context)
        {
        }

        public override async Task<IHandlerResponse<Response>> ExecuteAsync(Query query, CancellationToken ct)
        {
            var orders = await DbContext
                .Orders
                .ToListAsync(ct);

            return Success(new Response(orders));
        }
    }
}
```

Here is an example of **Command handler** with built-in [Fluent Validation](https://fluentvalidation.net/) and fire and forget style:

```csharp
public static class ConfirmAllOrders
{
    public sealed class Command : ICommand
    {
        public string Name { get; set; } = "";
    }

    public sealed class MyValidator : Validator<Command>
    {
        public MyValidator()
        {
            RuleFor(x => x.Name)
                .MinimumLength(5)
                .WithMessage("Order name is too short!");
        }
    }

    public sealed class Handler : Abstractions.CommandHandler<Command>
    {
        public Handler(IHandlerContext context) : base(context)
        {
        }

        public override async Task<IHandlerResponse> ExecuteAsync(Command command, CancellationToken ct)
        {
            var orders = await DbContext
                   .Orders
                   .ToListAsync(ct);

            orders.ForEach(x => x.SetConfrimed());

            await DbContext.SaveChangesAsync(ct);

            return Success();
        }
    }
}
```

Handlers allow 3 possible responses: 

1. Response without content:

```csharp
return Success()
``` 

2. Response with some content:

```csharp
return Success(responseObj)
``` 

3. An error*: 

```csharp
return Error("I felt a great disturbance in the Force, as if millions of voices suddenly cried out in terror and were suddenly silenced. I fear something terrible has happened.")
```

*soon to be implemented

Here is an example of running it from **Azure Functions**:

```csharp
public class ConfirmAllOrdersFunction : FunctionBase<ConfirmAllOrdersFunction>
{

    public ConfirmAllOrdersFunction(ILogger logger) : base(logger)
    {
    }

    [Function(nameof(ConfirmAllOrdersFunction))]
    public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
    {
        var command = new ConfirmAllOrders.Command();

        await ExecuteAsync<ConfirmAllOrders.Command>(command, req.FunctionContext);
    }
}
```


:fire: Interested? 
:fire: Checkout the complete source code on Github [FastArchitecture](https://github.com/kedzior-io/fast-architecture)