在 .NET Core Web API 中,控制器和路由是實現 API 請求的核心組件。控制器負責處理 HTTP 請求並生成對應的回應,而路由則決定每個請求應該被哪個控制器處理。本篇文章將深入探討如何在 .NET Core Web API 中配置控制器路由,以及設計路由時應該考慮的重點。
Controller
作為結尾,例如 ProductController
或 OrderController
。在 .NET Core Web API 中,路由通常有兩種設定方式:
在 ASP.NET Core Web API 中,傳統的路由模式也可以透過 Startup.cs
來進行配置。這種方式一般適用於簡單的專案,或是對於不需要非常自定義路徑的場景。
在 Startup.cs
的 Configure
方法中,我們可以設置一個簡單的預設路由:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "api/{controller=Home}/{action=Index}/{id?}");
});
在這裡,我們定義了預設的路由規則:
{controller=Home}
:預設控制器為 HomeController
。{action=Index}
:預設動作為 Index
。{id?}
:id
是可選參數。這種配置方式雖然簡單,但靈活性不如屬性路由,特別是在 API 設計中,屬性路由能更直觀地表現出 API 的資源路徑和操作。
屬性路由是透過將路由資訊直接標註在控制器與動作方法上來進行設定的。它提供了非常靈活且可讀性高的方式來設定路由。屬性路由適合 API 服務,因為 API 路徑往往需要明確且可控。
[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
// GET api/product
[HttpGet]
public IEnumerable<Product> GetProducts()
{
// 取得所有產品
}
// GET api/product/{id}
[HttpGet("{id}")]
public ActionResult<Product> GetProductById(int id)
{
// 依據 ID 取得特定產品
}
// POST api/product
[HttpPost]
public ActionResult CreateProduct(Product product)
{
// 新增一個產品
}
}
在這個範例中,[Route("api/[controller]")]
會將所有請求 /api/product
映射到 ProductController
。[controller]
是一個佔位符,會自動匹配控制器名稱(去掉 "Controller" 後綴)。
[HttpGet]
:處理 GET 請求,api/product
對應 GetProducts
方法。[HttpGet("{id}")]
:處理帶有 id
參數的 GET 請求,路徑會是 api/product/{id}
,對應 GetProductById
方法。[HttpPost]
:處理 POST 請求,路徑為 api/product
,用來新增產品。除了基本的路由配置,屬性路由允許我們更靈活地控制路徑與參數,以下是一些進階的設定範例:
[Route("api/[controller]")]
[ApiController]
public class OrderController : ControllerBase
{
// GET api/order/{orderId}/items
[HttpGet("{orderId}/items")]
public ActionResult<IEnumerable<OrderItem>> GetOrderItems(int orderId)
{
// 根據訂單 ID 取得所有訂單項目
}
// PUT api/order/{orderId}/item/{itemId}
[HttpPut("{orderId}/item/{itemId}")]
public ActionResult UpdateOrderItem(int orderId, int itemId, [FromBody] OrderItem updatedItem)
{
// 根據訂單 ID 與項目 ID 更新訂單項目
}
}
這裡的路由變得更為具體:GET api/order/{orderId}/items
用於查詢訂單項目,而 PUT api/order/{orderId}/item/{itemId}
則用於更新特定訂單的特定項目。這種設計可以清楚地表示資源之間的層次結構。
路由的唯一性與可讀性
每個路徑應該是唯一且可識別的。在設計 API 時,路徑應清楚地表達資源與操作。例如,針對產品資源的 API,可以這樣設計:
GET /api/products
:獲取所有產品GET /api/products/{id}
:根據 ID 獲取特定產品POST /api/products
:新增產品PUT /api/products/{id}
:更新特定產品DELETE /api/products/{id}
:刪除特定產品這樣的路由設計簡潔且符合 RESTful API 標準。
版本控制
當我們設計 API 時,版本控制是必須考慮的問題,特別是在需要長期維護和更新的系統中。可以通過路徑來進行版本控制,例如:
[Route("api/v1/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
// v1 的 API
}
[Route("api/v2/[controller]")]
[ApiController]
public class ProductV2Controller : ControllerBase
{
// v2 的 API,可能改變了部分行為或返回結構
}
這樣的版本控制確保了 API 的向後兼容性,避免了新版本 API 改動導致舊版本的應用無法正常工作。
多個參數與路由模板
當需要在 URL 中傳遞多個參數時,可以通過路由模板來靈活設計。例如,在訂單和訂單項目中,可以這樣設計:
[HttpGet("order/{orderId}/item/{itemId}")]
public ActionResult<OrderItem> GetOrderItem(int orderId, int itemId)
{
// 根據訂單 ID 和項目 ID 取得訂單項目
}
路徑 /order/{orderId}/item/{itemId}
清楚地表示了訂單與訂單項目之間的關聯。
URL 可預測性
設計 API 路徑時應保持一致性與可預測性,這樣開發者在使用 API 時能夠更容易理解。例如,對於不同的資源類型,應該遵循相似的路由模式,如 /api/orders
和 /api/products
,讓使用者能夠直觀預測資源路徑。
/api/products
清楚地表達了資源的性質(產品),避免使用過多的動詞,如 /api/getAllProducts
。GET
、POST
、PUT
、DELETE
),避免將動作放入 URL 中。在今天的文章中,我們深入探討了控制器與路由的設定,特別是屬性路由與傳統路由的配置方式。在設計 API 時,路由應該是簡潔、可讀、可預測並且遵循 RESTful 的原則。同時,我們還討論了路由設計時應該考慮的版本控制與參數管理。希望通過這篇文章,你能夠更好地設計清晰且有效的 API 路由。