繁体   English   中英

REST API设计:用于接收和更新资源的不同粒度

[英]REST API design: different granularity for receiving and updating resources

我正在创建REST API。 其中,有一种名为company的资源类型,它具有相当多的属性/字段。

处理company资源时的两个常见用例是:

  • 使用一个请求加载整个公司及其所有属性
  • 更新公司的(相对较小的)属性集, 但不能同时更新所有属性

我提出了两种不同的API设计方法,需要选择其中一种方法(可能还有更好的方法,所以请随意评论):


1.使用子资源进行细粒度更新

由于公司的属性可以分为不同类别(例如街道,城市和州代表地址......电话,邮件和传真代表联系信息等等),一种方法可以是使用以下路线:

/company/id :可用于使用GET获取整个公司

/company/id/address :可用于使用PUT更新地址信息(街道,城市......)

/company/id/contact :可用于使用PUT更新联系信息(电话,邮件...)

等等。

但是:在/company/id/address这样的子资源上使用GET永远不会发生。 同样,更新/company/id本身也永远不会发生(参见上面的用例)。 我不确定这种方法是否遵循REST的思想,因为我使用不同的URL加载和操作相同的数据。

2.使用HTTP PATCH进行细粒度更新

在这种方法中,没有用于部分更新的额外路由。 相反,只有一个端点:

/company/id :可用于使用GET获取整个公司,同时使用PATCH更新资源的子集(地址,联系信息等)。


从技术角度来看,我很确定这两种方法都能正常工作。 但是,我不想以不应该使用的方式使用REST。 你更喜欢哪种方法?

您是否真的知道GET响应中包含的每个字段? 如果没有,那么为地址和联系人创建自己的资源不仅仅是好的。 也许您稍后会找到一个可以重用这些资源的进一步用例。

此外,您还可以在资源中嵌入其他资源。 JSON HAL )fe明确地提供了一个_embedded属性,您可以在其中嵌入fe子资源的当前状态。 具有嵌入资源的虚构公司资源的简化类似HAL的JSON表示可能如下所示:

{
    "name":"Test Company",
    "businessType":"PLC",
    "foundingYear": 2010,
    "founders": [
        {
            "name": "Tim Test",
            "_links": {
                "self": {
                    "href": "http://example.org/persons/1234"
                }
            }
        }
    ],
    ...
    "_embedded": {
        "address": {
            "street": "Main Street 1",
            "city": "Big Town",
            "zipCode": "12345",
            "country": "Neverland"
            "_links": {
                "self": {
                    "href": "http://example.org/companies/someCompanyId/address/1"
                },
                "googleMaps": {
                    "href": "http://maps.google.com/?ll=39.774769,-74.86084"
                }
            }
        },
        "contacts":  {
            "CEO": {
                "name": "Maria Sample",
                ...
                "_links": {
                    "self": {
                        "href": "http://example.org/persons/1235"
                    }
                }
            },
            ...
        }
    }
}

因此,通过向特定资源的封闭URI发送PUT请求,可以更新嵌入式资源。 由于GET请求我被缓存,您可能需要提供更细粒度的缓存设置(带有条件GET请求,也就是If-Modified-Since或ETAG头字段)来检索更新后的实际状态。 这些头应该考虑整个资源(包括嵌入一次)以返回更新的状态。

关于PUTPATCH的“部分更新”:

虽然PUT的语义相当清楚,但PATCH通常只是通过向服务发送某些属性的新状态而与部分更新混淆。 然而, 本文描述了PATCH应该做什么。

简而言之,对于PATCH请求,客户端负责比较资源的当前状态并计算将当前资源转换为期望状态的必要步骤。 在计算步骤之后,请求必须包含服务器必须理解的指令才能执行这些指令,从而产生更新的版本。 此外, PATCH请求是原子的 - 要么所有指令都成功,要么无。 这会为此请求添加一些事务要求。

在这种特殊情况下,我使用PATCH而不是子资源方法。 首先,这不是一个真正的子资源。 这只是为了消除更新整个大实体(资源)的问题而引入的虚假抽象。 PATCH是REST兼容,成熟且通用的方法。

和(IMO 最终比率 ),想象你需要以某种方式扩展公司(通过添加杂志,场地,CTO,等等)。 您是否要添加新端点以使客户端能够更新此新添加的资源部分? 怎么结束? 具有无人理解的多个端点。 使用PATCH您的API已准备好用于公司的新元素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM