REST - 在保持控制的同时减少请求的策略

时间:2014-03-25 12:58:49

标签: rest restful-architecture

假设我想以RESTful方式建模IP地址和端口的关系。 IP地址包含许多端口,而端口只能有一个IP地址。此外,IP地址在该域中是唯一的地址,而端口在其IP地址中的端口号是唯一的。

对此进行建模的潜在策略是什么?我可以想到三个都有优点和缺点。

单独资源

维护两者的完全独立资源,并通过URL结构表示关系,并允许通过链接进行发现。

GET .../ipaddress/{address}/

{
    "ipaddress": "1.2.3.4",
    "ipversion": "v4",
    "links": [
        {
            "rel": "port"
            "link": "/ipaddress/1.2.3.4/ports/1234"
        },
        {
            "rel": "port"
            "link": "/ipaddress/1.2.3.4/ports/1235"
        },
        {
            "rel": "port"
            "link": "/ipaddress/1.2.3.4/ports/1236"
        }
    ]
}


GET .../ipaddress/{address}/port/{portnumber}

{
    "port":1234,
    "protocol":"unknown"
    ...other data here
}

优点

  • 精确映射到问题的资源的逻辑表示。
  • 允许将GET / POST / PUT / DELETE等HTTP方法不仅应用于IP地址,还应用于IP地址中的端口。

缺点

  • 要检索IP地址的所有端口,我必须发出N + 1个请求。一个请求IP地址获取到所有端口的链接,然后是N个后续请求每个端口资源。

嵌入式资源

将所有端口对象嵌入IP地址对象中。

GET .../ipaddress/{id}/


{
    "ipaddress": "1.2.3.4",
    "ipversion": "v4",
    "ports": [
        {
            "port": 1234,
            "protocol": "unknown",
             otherdata....
        },
        {
            "port": 1235,
            "protocol": "unknown"
             otherdata....
        },
        {
            "port": 1234,
            "protocol": "unknown"
             otherdata....
        }
    ]
}

优点

  • 只需一个请求即可检索IP地址的所有端口对象。

缺点

  • 无法再发出操作端口对象的单独请求。例如,如何从IPAddress中删除单个端口?我可以发出一个PUT请求,用删除的端口替换整个IP地址,或者做一些delta,但这看起来很笨拙。
  • 可能导致大量数据,例如,如果端口对象包含有关打开它的应用程序的其他信息。

混合方法

创建单独的资源,但在ipaddress中的链接对象中,嵌入来自该资源的一些数据,在这种情况下是端口号。

GET .../ipaddress/{id}

{
    "ipaddress": "1.2.3.4",
    "ipversion": "v4",
    "links": [
        {
            "port": 1234,
            "rel": "port",
            "link": "/ipaddress/1.2.3.4/ports/3"
        },
        {
            "port": 1235,
            "rel": "port",
            "link": "/ipaddress/1.2.3.4/ports/3"
        },
        {
            "port": 1236,
            "rel": "port",
            "link": "/ipaddress/1.2.3.4/ports/3"
        }
    ] }

GET ... / ipaddress / {id} / port / {portnumber}

Remains the same as the first example.

优点

  • 允许在单个请求中获取某些数据。
  • 允许我向表示端口的URI发出GET / PUT / POST / DEL要求。

缺点

  • 我已明确选择在“链接摘要”中表示哪些数据。如果客户想知道所有端口的所有协议列表,他们仍然必须执行N + 1个请求。

我相信像JSON+HAL之类的东西使用混合方法,因为它们嵌入了包含数据的其他资源的链接。但客户是否可以选择显示的内容?

如果我不使用任何嵌入数据,我最终会收到太多请求,如果我嵌入了所有内容,我最终没有能够操纵子资源的细粒度控制。还有其他建模方法吗?

我知道这是一个非常简单的例子,因为端口中没有大量数据。但这可以应用于具有依赖关系的任何两个对象。

由于

1 个答案:

答案 0 :(得分:1)

在queryString中使用HAL + JSON嵌入资源及其自己的链接和字段过滤器。

GET /ipaddress/1.2.3.4?fields="ipaddress,inversion,ports:[port,protocol,otherdata]"

{
    "ipaddress": "1.2.3.4",
    "ipversion": "v4",
    "_embedded": {
        "ports": {
            "items": [
                {
                    "port": 1234,
                    "protocol": "unknown",
                     otherdata....
                    "_links": {
                        "self": {
                            "href": "/ipaddress/1.2.3.4/ports/1234"
                        }
                    }
                },
                {
                    "port": 1235,
                    "protocol": "unknown"
                     otherdata....
                    "_links": {
                        "self": {
                            "href": "/ipaddress/1.2.3.4/ports/1235"
                        }
                    }
                },
                ...
            ],
            "_links": {
                "self": {
                    "href": "/ipaddress/1.2.3.4/ports"
                }
            }
        }
    },
    "_links": {
        "self": {
            "href": "/ipaddress/1.2.3.4"
        }
    }
}

顺便说一下。目前的实施仅取决于您的需求......

是的,客户可以选择,您可以添加元数据(如链接关系,微数据,微格式等...)到您的媒体格式,您可以忽略部分响应。您可以发送包含输入字段的结果的复杂链接,您可以使用它们设置链接参数,例如queryString中的字段过滤器等等...是的,这将使实现更难,您必须使用它很多,但我想你不会毫不费力地期待完整的代码...

还有很多其他媒体类型,例如:JSON-LD,集合+ json,警笛等......你可以根据需要检查它们,也许他们的方法对你更好......