如何说操作改变了RESTAPI中的另一个资源?

如何说操作改变了RESTAPI中的另一个资源?,rest,Rest,我想知道在RESTAPI(或类似REST的API)中,应该如何处理对其他资源有影响的资源修改 为了清楚起见,我将以一项法案为例。账单包含几行,每行都有一个金额。账单还有一个属性,说明总金额,即所有行的金额之和 使用JSON的账单表示可以是: { id: 156, amount: 12, lines: [ 1: { label : 'Item 1' amount: 8 } 2: {

我想知道在RESTAPI(或类似REST的API)中,应该如何处理对其他资源有影响的资源修改

为了清楚起见,我将以一项法案为例。账单包含几行,每行都有一个金额。账单还有一个属性,说明总金额,即所有行的金额之和

使用JSON的账单表示可以是:

{
    id: 156,
    amount: 12,
    lines: [
        1: {
            label : 'Item 1'
            amount: 8
       }
       2: {
            label: 'Item 2',
            amount: 4
        }
    ]
}
更新行并通知账单金额已更改的最佳方式是什么

我提出了一些想法,它们都有优点和缺点

解决方案1:使用一种资源

这个解决方案来自这样一个问题:“资源是否应该对其他资源产生影响?” 回答“否”将导致对账单及其行仅使用一种资源。这允许在账单资源上使用补丁。 此外,我们可以说,没有行的法案毫无意义

请求

PATCH api.something.com/bills/156
{
    lines: [
        1: {
             amount: 4
        }
    ]
}
POST api.something.com/bills/156/lines
{
    label: 'Item 156',
    amount: 10
}
PATCH api.something.com/bills/156/lines/
{
    amount: 5
}
DELETE api.something.com/bills/156/lines/2
PATCH api.something.com/bills/156/lines/1
{
    amount: 5
}
或者,使用

回应

HTTP/1.1 200 Success
{
 id: 156,
 amount: 8,
 lines: [
     1: {
         label : 'Item 1'
         amount: 4
     }
     2: {
         label: 'Item 2',
         amount: 4
     }
 ]
}
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 200 Success
{
    amount:5,
    label: "Item 1",
    "_links": {
        "bill": { 
            "href": "/bill/156",
            hasChanged: true
        }
    }
}
优点:

  • 一种资源
  • 不需要处理嵌入式资源
  • 如果行订单发生变化(删除或添加),我们将使用新订单
缺点:

  • 取消api.something.com/bills/156/lines上关于行添加的超级便利帖子
  • 在api.something.com/bills/156/lines/1上松开超级便捷的删除/修补程序以进行行删除/修改
解决方案2:调用子资源并重定向

如果我们同意为行使用子资源,一个解决方案是使用303重定向响应,如下所示

行加法

请求

PATCH api.something.com/bills/156
{
    lines: [
        1: {
             amount: 4
        }
    ]
}
POST api.something.com/bills/156/lines
{
    label: 'Item 156',
    amount: 10
}
PATCH api.something.com/bills/156/lines/
{
    amount: 5
}
DELETE api.something.com/bills/156/lines/2
PATCH api.something.com/bills/156/lines/1
{
    amount: 5
}
回应

HTTP/1.1 200 Success
{
 id: 156,
 amount: 8,
 lines: [
     1: {
         label : 'Item 1'
         amount: 4
     }
     2: {
         label: 'Item 2',
         amount: 4
     }
 ]
}
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 200 Success
{
    amount:5,
    label: "Item 1",
    "_links": {
        "bill": { 
            "href": "/bill/156",
            hasChanged: true
        }
    }
}
线路更新

请求

PATCH api.something.com/bills/156
{
    lines: [
        1: {
             amount: 4
        }
    ]
}
POST api.something.com/bills/156/lines
{
    label: 'Item 156',
    amount: 10
}
PATCH api.something.com/bills/156/lines/
{
    amount: 5
}
DELETE api.something.com/bills/156/lines/2
PATCH api.something.com/bills/156/lines/1
{
    amount: 5
}
回应

HTTP/1.1 200 Success
{
 id: 156,
 amount: 8,
 lines: [
     1: {
         label : 'Item 1'
         amount: 4
     }
     2: {
         label: 'Item 2',
         amount: 4
     }
 ]
}
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 200 Success
{
    amount:5,
    label: "Item 1",
    "_links": {
        "bill": { 
            "href": "/bill/156",
            hasChanged: true
        }
    }
}
行删除

请求

PATCH api.something.com/bills/156
{
    lines: [
        1: {
             amount: 4
        }
    ]
}
POST api.something.com/bills/156/lines
{
    label: 'Item 156',
    amount: 10
}
PATCH api.something.com/bills/156/lines/
{
    amount: 5
}
DELETE api.something.com/bills/156/lines/2
PATCH api.something.com/bills/156/lines/1
{
    amount: 5
}
回应

HTTP/1.1 200 Success
{
 id: 156,
 amount: 8,
 lines: [
     1: {
         label : 'Item 1'
         amount: 4
     }
     2: {
         label: 'Item 2',
         amount: 4
     }
 ]
}
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 200 Success
{
    amount:5,
    label: "Item 1",
    "_links": {
        "bill": { 
            "href": "/bill/156",
            hasChanged: true
        }
    }
}
缺点:

  • 行是账单的一部分,也是子资源
  • 在添加、删除或修改行时,必须使用行获取票据资源
  • 仅适用于我们不太关心的资源(子资源或没有有趣内容)
优点:

  • 使用post、put和delete
解决方案3:使用链接

第三种选择是使用链接,例如使用。 HAL允许向链接添加属性。引入hasChange属性可以解决这个问题

行金额更新的工作原理如下:

请求

PATCH api.something.com/bills/156
{
    lines: [
        1: {
             amount: 4
        }
    ]
}
POST api.something.com/bills/156/lines
{
    label: 'Item 156',
    amount: 10
}
PATCH api.something.com/bills/156/lines/
{
    amount: 5
}
DELETE api.something.com/bills/156/lines/2
PATCH api.something.com/bills/156/lines/1
{
    amount: 5
}
回应

HTTP/1.1 200 Success
{
 id: 156,
 amount: 8,
 lines: [
     1: {
         label : 'Item 1'
         amount: 4
     }
     2: {
         label: 'Item 2',
         amount: 4
     }
 ]
}
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 303 See other
Location: https://api.something.com/bills/156
HTTP/1.1 200 Success
{
    amount:5,
    label: "Item 1",
    "_links": {
        "bill": { 
            "href": "/bill/156",
            hasChanged: true
        }
    }
}
优点:

  • 为非子资源工作
  • 在更新多个资源时工作
缺点:

  • 处理链接。()
我很想知道是否有人可以建议支持或反对其中一种解决方案,因为它们对我来说都很有趣