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

问题描述 投票:0回答:2

我正在创建 REST API。其中,有一种名为

company
的资源类型,它具有相当多的属性/字段。

处理

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

  • 通过一个请求加载整个公司及其所有属性
  • 更新公司的一组(相对较小的)属性,但绝不会同时更新所有属性

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


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

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

/company/id
:可用于使用
GET

获取整个公司

/company/id/address
:可用于使用
PUT

更新地址信息(街道、城市...)

/company/id/contact
:可用于使用
PUT

更新联系信息(电话、邮件...)

等等。

但是:在像

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

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

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

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


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

rest http web-services api-design
2个回答
3
投票

您真的一直需要

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

此外,您还可以在资源中嵌入其他资源。 JSON HAL () f.e.明确提供了一个

_embedded
属性,您可以在其中嵌入 f.e. 的当前状态。子资源。具有嵌入式资源的虚构公司资源的简化的类似 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 标头字段)以在更新后检索实际状态。这些标头应考虑整个资源(包括嵌入一次),以便返回更新后的状态。

关于“部分更新”的
PUT
PATCH

虽然

PUT
的语义相当清晰,但
PATCH
经常与仅将某些属性的新状态发送到服务的部分更新混淆。 这篇文章描述了
PATCH
真正应该做什么。

简而言之,对于

PATCH
请求,客户端负责比较资源的当前状态并计算将当前资源转换为所需状态所需的步骤。计算步骤后,请求将必须包含服务器必须理解的指令才能执行这些指令,从而生成更新的版本。此外,
PATCH
请求是原子的——所有指令要么成功,要么全部失败。这为此请求添加了一些交易要求。


2
投票

在这种特殊情况下,我会使用

PATCH
而不是子资源方法。首先,这不是真正的子资源。它只是为了消除更新整个大实体(资源)的问题而引入的虚假抽象。而
PATCH
是一种与 REST 兼容、完善且通用的方法。

并且(IMO 终极比例),想象一下您需要以某种方式扩展公司(通过添加杂志、场地、首席技术官等)。您是否会添加一个新端点以使客户端能够更新资源的新添加部分?结局如何?具有无人理解的多个端点。有了

PATCH
,您的 API 就可以适应公司的新元素了。

© www.soinside.com 2019 - 2024. All rights reserved.