Core API Routing

Routing is the mechanism that decides which action method handles a particular HTTP request. When a request arrives at /api/books/5, the routing system reads the URL, matches it to the right controller and action method, and calls it. Understanding routing is essential for designing clean and predictable API URLs.

How Routing Works

ASP.NET Core routing works in two steps:

HTTP Request: GET /api/books/5
     |
     v
[ Route Matching ]
     |
     ├── Is there a controller with route "api/books"?  → YES: BooksController
     └── Is there an action with route "{id}" and [HttpGet]? → YES: GetById(int id)
     |
     v
[ Action Method Called ]
GetById(id: 5) executes
     |
     v
HTTP Response: 200 OK + Book data

Attribute Routing

ASP.NET Core Web API uses attribute routing by default. Routes are defined directly on the controller class and action methods using attributes.

[ApiController]
[Route("api/[controller]")]          // ← Controller-level route: /api/books
public class BooksController : ControllerBase
{
    [HttpGet]                        // → GET /api/books
    public IActionResult GetAll() { ... }

    [HttpGet("{id}")]                // → GET /api/books/5
    public IActionResult GetById(int id) { ... }

    [HttpPost]                       // → POST /api/books
    public IActionResult Create([FromBody] Book book) { ... }

    [HttpPut("{id}")]                // → PUT /api/books/5
    public IActionResult Update(int id, [FromBody] Book book) { ... }

    [HttpDelete("{id}")]             // → DELETE /api/books/5
    public IActionResult Delete(int id) { ... }
}

The [controller] Token

In [Route("api/[controller]")], the [controller] token is automatically replaced by the class name minus the word "Controller".

Class NameRoute Token [controller]Final URL Prefix
BooksControllerbooks/api/books
AuthorsControllerauthors/api/authors
OrdersControllerorders/api/orders

Route Parameters

Route parameters are variable parts of the URL. They are defined with curly braces {} in the route template and automatically extracted and passed to the action method.

[HttpGet("{id}")]
public IActionResult GetById(int id)
{
    // id is automatically pulled from the URL
    var book = _books.FirstOrDefault(b => b.Id == id);
    if (book == null) return NotFound();
    return Ok(book);
}

Request: GET /api/books/3id = 3

Multiple Route Parameters

[HttpGet("{category}/{id}")]
public IActionResult GetByCategoryAndId(string category, int id)
{
    var book = _books.FirstOrDefault(b => b.Category == category && b.Id == id);
    if (book == null) return NotFound();
    return Ok(book);
}

Request: GET /api/books/Technology/3category = "Technology", id = 3

Query String Parameters

Query strings appear after the ? in a URL. They are used for filtering, sorting, and pagination. ASP.NET Core automatically binds query string values to action method parameters.

[HttpGet]
public IActionResult GetAll(string? category, bool? isAvailable)
{
    var books = _books.AsQueryable();

    if (!string.IsNullOrEmpty(category))
        books = books.Where(b => b.Category == category);

    if (isAvailable.HasValue)
        books = books.Where(b => b.IsAvailable == isAvailable.Value);

    return Ok(books.ToList());
}
Request URLResult
GET /api/booksAll books
GET /api/books?category=TechnologyOnly Technology books
GET /api/books?isAvailable=trueOnly available books
GET /api/books?category=Technology&isAvailable=trueAvailable Technology books

Custom Route Names

Instead of using [controller], a custom route name can be specified directly:

[Route("api/bookstore")]           // → /api/bookstore
public class BooksController : ControllerBase
{
    [HttpGet("all")]               // → GET /api/bookstore/all
    public IActionResult GetAll() { ... }

    [HttpGet("find/{id}")]         // → GET /api/bookstore/find/5
    public IActionResult GetById(int id) { ... }
}

Route Constraints

Route constraints restrict the type of value a route parameter accepts. This prevents invalid requests from reaching the action method.

[HttpGet("{id:int}")]          // id must be an integer
public IActionResult GetById(int id) { ... }

[HttpGet("{title:alpha}")]     // title must contain only letters
public IActionResult GetByTitle(string title) { ... }

[HttpGet("{id:int:min(1)}")]   // id must be integer, minimum value 1
public IActionResult GetByPositiveId(int id) { ... }
ConstraintMeaningExample
:intMust be an integer{id:int}
:alphaMust be letters only{name:alpha}
:boolMust be true or false{flag:bool}
:guidMust be a GUID{token:guid}
:min(n)Minimum value{id:int:min(1)}
:maxlength(n)Max string length{name:maxlength(50)}

How MapControllers() Enables Routing

In Program.cs, the MapControllers() call tells ASP.NET Core to scan all controllers and register their routes.

var app = builder.Build();

app.UseRouting();
app.UseAuthorization();
app.MapControllers();   // ← registers all controller routes

app.Run();

Without MapControllers(), the API cannot match any URL to any action method — every request returns a 404.

BookStore API – Route Summary

Method   URL                              Action Method
───────────────────────────────────────────────────────────────────
GET      /api/books                       GetAll()
GET      /api/books?category=Technology   GetAll(category: "Technology")
GET      /api/books/5                     GetById(5)
POST     /api/books                       Create(book)
PUT      /api/books/5                     Update(5, book)
DELETE   /api/books/5                     Delete(5)

Key Points

  • ASP.NET Core Web API uses attribute routing — routes are defined on the controller and action method using attributes.
  • [Route("api/[controller]")] sets the base URL using the controller class name.
  • Route parameters use curly braces: {id}, and they are automatically mapped to action method parameters.
  • Query strings are automatically bound to optional parameters with matching names.
  • Route constraints (:int, :alpha) restrict what values a route parameter can accept.
  • MapControllers() in Program.cs activates all controller routes.

Leave a Comment