如何符合REST URL模式而不是方法名称

时间:2018-06-11 20:12:18

标签: rest asp.net-web-api

假设我有一些我想从Db查询的业务实体,并在Web API中执行此操作。说,客户和订单。每个订单只能有一个客户。

说我想得到 - 给定客户的所有订单
- 对于给定的订单,返回包含一些客户属性的对象,以及该客户5最近的订单#'s

https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md#71-url-structure

我倾向于使用这样的方法名称。

OrdersController:
- GetOrders
- GetordersforCustomer(int CustomerId)
- GetOrderWithCustomerInfo(int CustomerId)

CustomerController
- GetCustomer(int id)
- GetCustomerWithinZipcode

因此,使用这样的API控制器方法并不遵循其他地方看到的REST“指南”,对吗?如果没有,我怎么能重构我的控制器以适应标准的HTTP方法名称,特别是当有相关实体时?

例如,我需要一个调用,它返回一个对象,该对象不仅包含订单中的属性,还包含当前订单中客户的前5个订单。我需要一个获取订单结果的方法,但也需要一种获取不同类型订单结果的方法 - 一个具有来自客户和/或其他一些实体的某些属性。

我正在谈论的例子 - 仅使用http动词,但使用相关实体 https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful 但是你如何处理关系?如果关系只能存在于另一个资源中,则RESTful原则可提供有用的指导。我们来看一个例子吧。 Enchant中的票证包含许多消息。这些消息可以按逻辑方式映射到/ ticket端点,如下所示:

GET /tickets/12/messages - Retrieves list of messages for ticket #12
GET /tickets/12/messages/5 - Retrieves message #5 for ticket #12
POST /tickets/12/messages - Creates a new message in ticket #12
PUT /tickets/12/messages/5 - Updates message #5 for ticket #12
PATCH /tickets/12/messages/5 - Partially updates message #5 for ticket #12
DELETE /tickets/12/messages/5 - Deletes message #5 for ticket #12

1 个答案:

答案 0 :(得分:0)

问题广泛且基于意见。

也就是说,没有必要重组控制器。

使用属性路由进行研究。

参考Routing to controller actions in ASP.NET Core

鉴于相关指南,潜在路线的示例可能如下所示。

[Route([controller])]
OrdersController:
    //Matches GET orders
    [HttpGet]
    GetOrders()

    //Matches GET customers/1234/orders
    [HttpGet(~/customers/{customerId:int}/orders)]
    GetOrdersForCustomer(int customerId)

    Matches GET orders/1324/customer/5678
    [HttpGet({orderId:int}/customer/{customerId:int})]
    GetOrderWithCustomerInfo(int orderId, int customerId)

[Route([controller])]
CustomersController
    //Matches GET customers
    [HttpGet]
    GetCustomers()

    //Matches GET customers/1234
    [HttpGet("{id:int}")]
    GetCustomer(int id)

    //Matches GET zipcodes/90210/customers
    [HttpGet("~/zipcodes/{zipCode:int}/customers")]
    GetCustomerWithinZipcode(int zipCode)