A Cleaner .NET Backend for React: Minimal APIs Organised With Carter

by

in

A React front-end paired with a .NET back-end is one of the most productive stacks around — but the two ends pull in different directions on structure. React gives you a clean component tree; the classic .NET controller stack, by comparison, can feel heavy for what is often a straightforward JSON API. Minimal APIs fixed the weight problem, and Carter fixes the one thing Minimal APIs left open: organisation. Here is the setup we reach for on modern React + .NET projects.

Why Minimal APIs — and where they get messy

Minimal APIs let you define an endpoint in a single expressive line, with far less ceremony than a controller. The trade-off shows up as the project grows: everything tends to pile into Program.cs, and a hundred app.MapGet(...) calls in one file is its own kind of mess. You have traded boilerplate for a lack of structure.

Carter: structure without the weight

Carter is a thin library over ASP.NET Core routing that reintroduces modularity without dragging back the full controller machinery. You group related endpoints into a module — a small class implementing ICarterModule — and Carter discovers and wires them up for you. Registration is two lines:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCarter();

var app = builder.Build();
app.MapCarter();
app.Run();

An endpoint module

Each feature gets its own module. Everything about “products” lives in one place, close together and easy to find:

public class ProductModule : ICarterModule
{
    public void AddRoutes(IEndpointRouteBuilder app)
    {
        var group = app.MapGroup("/api/products");

        group.MapGet("/", async (IProductService svc) =>
            Results.Ok(await svc.GetAllAsync()));

        group.MapGet("/{id:int}", async (int id, IProductService svc) =>
            await svc.FindAsync(id) is { } p
                ? Results.Ok(p)
                : Results.NotFound());

        group.MapPost("/", async (CreateProduct cmd, IProductService svc) =>
        {
            var created = await svc.CreateAsync(cmd);
            return Results.Created($"/api/products/{created.Id}", created);
        });
    }
}

Add a new feature area and you add a new module — you never touch a growing central file. That is the property that keeps a codebase pleasant to work in as it scales.

Validation that stays out of the handler

Carter integrates cleanly with FluentValidation, so input rules live in a validator rather than cluttering the endpoint. The handler stays focused on the happy path, and invalid requests are turned away with a proper problem response before your logic runs:

public class CreateProductValidator : AbstractValidator<CreateProduct>
{
    public CreateProductValidator()
    {
        RuleFor(x => x.Name).NotEmpty().MaximumLength(120);
        RuleFor(x => x.Price).GreaterThan(0);
    }
}

How it fits the React side

From React’s point of view this is just a clean, predictable JSON API — fetch or your query library of choice against /api/products, typed responses, standard status codes. The value of Carter is entirely on the back-end: your endpoints are grouped by feature the same way your React components are grouped by feature, so the two halves of the app mirror each other and a developer can move between them without re-learning the layout.

Why we like this stack

  • Low ceremony. Minimal APIs keep each endpoint to what it actually does.
  • Real structure. Carter modules keep features isolated and discoverable as the project grows.
  • Clean separation. Validation, handlers, and services stay in their own lanes.
  • A back-end shaped like the front-end. Feature-per-module on the server mirrors feature-per-folder in React.

Takeaway

Minimal APIs solved .NET’s boilerplate problem; Carter solves the organisation problem they left behind, without dragging back the weight of controllers. For a React front-end talking to a .NET back-end, it is a lightweight, tidy foundation that ages well. We build exactly this kind of React + .NET application for e-commerce and logistics platforms — get in touch if you are starting one or cleaning one up.