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 Name | Route Token [controller] | Final URL Prefix |
|---|---|---|
| BooksController | books | /api/books |
| AuthorsController | authors | /api/authors |
| OrdersController | orders | /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/3 → id = 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/3 → category = "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 URL | Result |
|---|---|
GET /api/books | All books |
GET /api/books?category=Technology | Only Technology books |
GET /api/books?isAvailable=true | Only available books |
GET /api/books?category=Technology&isAvailable=true | Available 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) { ... }
| Constraint | Meaning | Example |
|---|---|---|
:int | Must be an integer | {id:int} |
:alpha | Must be letters only | {name:alpha} |
:bool | Must be true or false | {flag:bool} |
:guid | Must 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()inProgram.csactivates all controller routes.
