DEV Community

Dhana
Dhana

Posted on

Minimal APIs vs. Controllers: It's Not About Which One Is Newer

Minimal APIs get discussed as the newer, leaner way to write ASP.NET Core endpoints, and Controllers as the older, more established approach. That framing makes it sound like a question of which one to switch to. In practice, the more useful question is which one fits a given endpoint or project, since the two solve different shaped problems.

The Same Endpoint, Two Ways

Consider a simple endpoint that fetches workflow role mappings for an employee, written first the familiar Controller way:

csharp
[ApiController]
[Route("api/[controller]")]
public class WorkFlowController : ControllerBase
{
private readonly IclsWorkFlow _workFlowDataAccess;

public WorkFlowController(IclsWorkFlow workFlowDataAccess)
{
    _workFlowDataAccess = workFlowDataAccess;
}

[HttpGet("get-add-rolemapping")]
public IActionResult GetAddRoleMapping(int employeeSlno, int createdBy)
{
    var result = _workFlowDataAccess.GetAddWorkFlows(employeeSlno, createdBy);
    return Ok(result);
}
Enter fullscreen mode Exit fullscreen mode

}

And the same behavior as a Minimal API:

csharp
app.MapGet("/api/workflow/get-add-rolemapping",
(int employeeSlno, int createdBy, IclsWorkFlow workFlowDataAccess) =>
{
var result = workFlowDataAccess.GetAddWorkFlows(employeeSlno, createdBy);
return Results.Ok(result);
});

Both versions do exactly the same thing. The Minimal API version skips the class, the routing attributes, and the constructor, registering the endpoint directly with a single call. The dependency, IclsWorkFlow, is still supplied automatically by the built-in DI container; it's simply passed as a parameter instead of arriving through a constructor.

Why Minimal APIs Exist at All

The Controller version carries a certain amount of structure regardless of how small the endpoint actually is: a class, class-level attributes, and a constructor, before a single line of the endpoint's own logic appears. For a genuinely small service, one with a handful of endpoints total, that structure adds more ceremony than the endpoints need. Minimal APIs were introduced specifically to remove that overhead for cases where it isn't earning its keep, such as small microservices, quick internal utilities, or a lightweight health-check endpoint sitting alongside a larger application.

Where the Trade-off Actually Shows Up

The comparison changes once there's more than one endpoint to manage. A workflow-related API with four related operations, written as Controller actions, keeps them together in one class:

csharp
public class WorkFlowController : ControllerBase
{
[HttpGet("get-add-rolemapping")]
public IActionResult GetAddRoleMapping(...) { ... }

[HttpGet("get-delete-rolemappings")]
public IActionResult GetDeleteRoleMappings(...) { ... }

[HttpPost("save-add-role-mapping")]
public IActionResult SaveAddRoleMapping(...) { ... }

[HttpPost("save-delete-role-mapping")]
public IActionResult SaveDeleteRoleMapping(...) { ... }
Enter fullscreen mode Exit fullscreen mode

}

Written as four separate Minimal API registrations, the same four operations would each need their own app.MapGet or app.MapPost call, typically sitting in Program.cs or a similarly central file:

csharp
app.MapGet("/api/workflow/get-add-rolemapping", (...) => { ... });
app.MapGet("/api/workflow/get-delete-rolemappings", (...) => { ... });
app.MapPost("/api/workflow/save-add-role-mapping", (...) => { ... });
app.MapPost("/api/workflow/save-delete-role-mapping", (...) => { ... });

As more modules and endpoints accumulate this way, Program.cs grows large and loses the natural grouping a Controller class provides for free. Minimal APIs can be organized into separate extension methods or files to manage this, but that's additional structure being reintroduced to solve a problem Controllers handle inherently, through the class itself acting as the grouping mechanism.

A Practical Way to Decide

The deciding question isn't which style is newer or more fashionable, but which shape the API actually has. A small, standalone service with a few endpoints and little shared context between them is a reasonable fit for Minimal APIs, gaining less ceremony without losing much organization, since there isn't much to organize in the first place. A larger, cohesive application with many related endpoints, shared dependencies, and common conventions across them tends to stay easier to navigate as a set of Controllers, where the class itself keeps related operations grouped as the codebase grows.

The two approaches aren't mutually exclusive within a single application, either. It's common to see Controllers handling the main, complex business logic of a large system, while a Minimal API endpoint or two handles something small and self-contained alongside it, such as a health check or a simple status endpoint that doesn't warrant its own class.

Takeaway

Choosing between Minimal APIs and Controllers is a question of fit, not of which one is more current. A handful of small, loosely related endpoints tend to suit Minimal APIs well, trading away structure that wasn't providing much value. A larger set of related endpoints, especially ones sharing dependencies and conventions, tends to stay more maintainable as Controllers, where the class itself does the organizational work that would otherwise have to be rebuilt some other way. The right choice depends on how many endpoints there are and how related they are to each other, not on which approach appeared more recently.

Top comments (0)