【问题标题】:Add a single or multiple API endpoints when accepting POST request?接受 POST 请求时添加单个或多个 API 端点?
【发布时间】:2018-12-17 14:44:02
【问题描述】:

我已经计划构建一个这样的多个服务端点来更新多个实体项。

/api/order(orderInfo) [httppost]
/api/orderChangeCurrency(orderCurrency) [httppost]
/api/orderChangeClientName(orderClientName) [httppost]

public class orderInfo()
{
public int orderID {get;set;}
public int orderType {get;set;}
}

public class orderCurrency()
{
public int orderID {get;set;}
public int currencyID {get;set;}
}

public class orderClientName()
{
public int orderID {get;set;}
public string firstName{get;set;}
public stringlastName{get;set;}
}

但我突然想到有一个端点来代替它来完成所有工作

/api/order(orderExtendedInfo) [httppost]

public class orderExtendedInfo()
{
public int orderID {get;set;}
public orderInfo? OrderInfo{get;set;}
public orderCurrency? OrderCurrency{get;set;}
public orderClientName? OrderClientName{get;set;}
}

在这种情况下,我将有一个业务逻辑,它会根据提供的信息(是否为空值)更新实体。

在这种特定情况下,是否有针对 API 端点的推荐做法或规则?

【问题讨论】:

  • 您在寻找哪种“推荐”方式?更具体
  • 我只是在寻找针对这种特殊情况的 API 设计实践。
  • 我认为你的方法没问题。唯一的问题是,如果您遵循 REST,那么您的方法有点错误。休息专注于资源,因此,您不应该在 on 方法中处理多个资源。但是,这只是“纯粹”的 REST 指南,我认为它在我的日常工作中应用不多。
  • @jpgrassi 当你说好的方法时,你指的是单个端点还是多个端点?

标签: api asp.net-web-api api-design


【解决方案1】:

嗯,这是一个相当广泛的问题,可能更适合http://programmers.stackexchange.com,但无论如何我都会放弃一些考虑。

首先,您的 API 设计应该面向 API 的用户。如果您的 API 是面向公众的 API,您可以考虑使用REST。它是一种广泛使用(且备受争议)的架构风格,许多程序员都习惯了这种风格。一个非常有用的关于设计 RESTful API 的建议列表可以是found here

其次,您应该考虑 API 的可消费性。以您的设计为例:消费者一个一个地更新实体是否合乎逻辑,还是一次更新一个或多个甚至所有实体更合乎逻辑?

第三,您必须考虑数据库事务。当所有实体都应该在一个原子操作中更新时,您不能提供三个端点。

就我个人而言,我非常喜欢 REST,所以我很乐意为您的用例提供一个示例。

示例

首先让我介绍一个新实体:

public class OrderLine 
{
    public int Id {get;set;}
    public int OrderId {get;set;}
    public int ProductId {get;set;}
    public int Quantity {get;set;}
    public decimal Price {get;set;}
}

端点

POST /api/orders                  # creates a new order 
GET  /api/orders                  # gets all orders
GET  /api/orders/1                # gets order 1
POST /api/orders/1/orderlines     # creates a new order line for order 1.
GET  /api/orders/1/orderlines/1   # gets order line 1 of order 1
GET  /api/orderlines/{id}         # gets order line 1

如果您需要在单个操作中更新多个实体,您可以这样做:

为更新创建模型:

public class EditOrder
{
    public int orderID {get;set;}
    public int orderType {get;set;}
    public int currencyID {get;set;}
    public string firstName{get;set;}
    public string lastName{get;set;}
}

然后使用这个端点

PUT  /api/orders/1 

还有这个方法

public IHttpActionResult Put(int id, EditOrder editOrder)
{
    // retrieve current Order, OrderCurrency and OrderClient
    // update the entities 
    // save entities
}

【讨论】:

  • 您对所有事实都是正确的。在更新订单时,它应该是 PUT 而不是 POST。关于端点的结构,您是对的,尤其是在以 /api/orders/{id}/orderlines 等格式放置订单时(似乎有重复/或类似的端点 /api/orders/1/orderlines/1 和 / api/orderlines/{id} )。我只是不确定是否不需要进行原子更新,在单个操作中更新多个实体或将其划分为多个端点(从最终用户的角度来看)是否更明智。从 BL 的角度来看,这将是完全不同的问题。
  • 例如developer.zendesk.com/rest_api/docs/core/tickets#update-ticket 基本上是在单个端点内更新整个票证(审计、cmets 等除外),这与您示例中的 orderline 类似。
  • 我添加了重复的端点,表示可以通过多个端点访问一个资源。
【解决方案2】:

我认为你应该像这样在业务层实现一个控制器动作方法和三个方法

[HttpPost]
[Route("api/order")]
public async Task<IHttpActionResult> SubmitOrder(OrderExtendedInfo info)
{
    var bl = new BusinessLayer();
    if(info.orderInfo.HasValue)
    {
        bl.UpdateOrderInfo(orderInfo);
    }
    if(info.orderCurrency.HasValue)
    {
        bl.UpdateOrderCurrency(orderCurrency);
    }
    if(info.orderClientName.HasValue)
    {
        bl.UpdateOrderClientName(orderClientName);
    }
}

【讨论】:

  • 在您的解决方案中,需要三个往返 DB 才能进行所有更新。但是可以说这不是问题,主要关心的是我应该有一个或多个 API 端点。
猜你喜欢
  • 2020-12-01
  • 1970-01-01
  • 2018-11-13
  • 1970-01-01
  • 2018-08-23
  • 1970-01-01
  • 2018-02-25
  • 2021-11-14
  • 2021-04-02
相关资源
最近更新 更多