Web 浏览器是否与 HatEoAS 兼容?
Are web browsers trivially HatEoAS compliant?
在现在著名的 blog post 中,REST 架构的发明者 Roy Fielding 批评了术语 RESTful 的误用。特别是,他区分了 RPC 和 REST 接口。
我对此的理解是,在RPC接口中,所有状态转换的方法(包括它们的位置和含义)都是客户端先验知道的,而在REST接口中,客户端和服务器只需要说话一种通用语言(具有具有先验语法和语义的共享媒体类型),它描述了应用程序状态和(位置 和含义 )状态转换的方法,以及实际可用的方法由客户端在 运行 时间发现。
当客户端-服务器情况是专门的东西时,我可以看到这是一个不平凡的约束,比如智能灯泡与其桥接口,但当客户端-服务器关系是网络浏览器和Web 服务器,上面的 RESTfulness 约束不是很容易满足吗?
这假设服务器可能传送的 JavaScript 被视为表示的一部分(因此可以在不破坏 RESTfulness 的情况下随意包含硬编码链接)。另一方面,也可以认为 browser+js 的组合才是真正的客户端,然后 RESTfulness 对 JS 客户端的设计施加了一个重要的约束。但是这个观点是不是有点被解读了?
这是对 JS 代码的重要约束。 JS 应该被认为是客户端而不是资源表示。的确,两者都是,但只是从两个不同的角度来看。当 JS 戴着它的 "resource representation" 帽子时,它是惰性的,什么都不做。当它戴着它的 "REST client" 帽子时,它作为资源表示的一部分就不再重要了。
硬编码链接不是唯一的问题:JS 代码连接字符串以使用内部信息构建链接也是一个问题。这些违反 REST 的行为会影响 "modifiability" 的 属性。当您考虑到 JS 代码和服务器实现通常作为同一项目的一部分开发时,这似乎不是问题。 URI 和客户端 URI 构建逻辑可以很容易地保持同步,对吧?但是,如果您有多个应用程序和它们自己的 JS 客户端共享一个服务器 API 实现怎么办?对 URI 的任何更改都会破坏很多客户端。
JS代码应该和任何其他客户端一样受相同规则的约束:链接应该来自服务器提供的资源,语义应该来自对媒体类型的共同理解。
具体示例
假设我们有一个资源/readinglist/,它被定义为一个书籍集合,看起来像这样:
{
[
{
"id":"GoT",
},
{
"id":"LOTR",
},
{
"id":"IT",
},
...
]
}
JS代码显示列表,如果用户点击某个项目,JS获取对应的"book"资源,显示更多细节:
获取/readinglist/IT
{
"id":"IT",
"author":"Stephen. R. R. King"
}
这是所谓的 "REST" api 中非常常见的模式。但是这里发生的事情是 JS 必须包含逻辑,表明您通过将书的 ID 附加到集合的 URL 来检索一本书。换句话说,客户端状态由带外信息驱动。您可能会争辩说,由于 JS 代码本身作为资源来自服务器,因此这并不是真正的带外信息。但是 JS 现在充当客户端,应该这样分析。
相比之下,考虑 /readinglist/ 资源的这种表示:
{
[
{
"id":"GoT",
"link:"/books/GoT"
},
{
"id":"LOTR",
"link:"/books/LOTR"
},
{
"id":"IT",
"link:"/books/IT"
},
...
]
}
现在 JS 不必知道如何连接 URLS。相反,它必须有逻辑表明您可以通过遵循集合表示中的 "link" URL 来获取书籍资源。这更复杂还是更不复杂?大致相同。关键区别在于,使用这种方法,客户端状态由超媒体驱动,基于媒体类型的约定语义。一旦确定并标准化了媒体类型及其处理规则,就可以在多个 API 中重复使用。
在现在著名的 blog post 中,REST 架构的发明者 Roy Fielding 批评了术语 RESTful 的误用。特别是,他区分了 RPC 和 REST 接口。
我对此的理解是,在RPC接口中,所有状态转换的方法(包括它们的位置和含义)都是客户端先验知道的,而在REST接口中,客户端和服务器只需要说话一种通用语言(具有具有先验语法和语义的共享媒体类型),它描述了应用程序状态和(位置 和含义 )状态转换的方法,以及实际可用的方法由客户端在 运行 时间发现。
当客户端-服务器情况是专门的东西时,我可以看到这是一个不平凡的约束,比如智能灯泡与其桥接口,但当客户端-服务器关系是网络浏览器和Web 服务器,上面的 RESTfulness 约束不是很容易满足吗?
这假设服务器可能传送的 JavaScript 被视为表示的一部分(因此可以在不破坏 RESTfulness 的情况下随意包含硬编码链接)。另一方面,也可以认为 browser+js 的组合才是真正的客户端,然后 RESTfulness 对 JS 客户端的设计施加了一个重要的约束。但是这个观点是不是有点被解读了?
这是对 JS 代码的重要约束。 JS 应该被认为是客户端而不是资源表示。的确,两者都是,但只是从两个不同的角度来看。当 JS 戴着它的 "resource representation" 帽子时,它是惰性的,什么都不做。当它戴着它的 "REST client" 帽子时,它作为资源表示的一部分就不再重要了。
硬编码链接不是唯一的问题:JS 代码连接字符串以使用内部信息构建链接也是一个问题。这些违反 REST 的行为会影响 "modifiability" 的 属性。当您考虑到 JS 代码和服务器实现通常作为同一项目的一部分开发时,这似乎不是问题。 URI 和客户端 URI 构建逻辑可以很容易地保持同步,对吧?但是,如果您有多个应用程序和它们自己的 JS 客户端共享一个服务器 API 实现怎么办?对 URI 的任何更改都会破坏很多客户端。
JS代码应该和任何其他客户端一样受相同规则的约束:链接应该来自服务器提供的资源,语义应该来自对媒体类型的共同理解。
具体示例
假设我们有一个资源/readinglist/,它被定义为一个书籍集合,看起来像这样:
{
[
{
"id":"GoT",
},
{
"id":"LOTR",
},
{
"id":"IT",
},
...
]
}
JS代码显示列表,如果用户点击某个项目,JS获取对应的"book"资源,显示更多细节:
获取/readinglist/IT
{
"id":"IT",
"author":"Stephen. R. R. King"
}
这是所谓的 "REST" api 中非常常见的模式。但是这里发生的事情是 JS 必须包含逻辑,表明您通过将书的 ID 附加到集合的 URL 来检索一本书。换句话说,客户端状态由带外信息驱动。您可能会争辩说,由于 JS 代码本身作为资源来自服务器,因此这并不是真正的带外信息。但是 JS 现在充当客户端,应该这样分析。
相比之下,考虑 /readinglist/ 资源的这种表示:
{
[
{
"id":"GoT",
"link:"/books/GoT"
},
{
"id":"LOTR",
"link:"/books/LOTR"
},
{
"id":"IT",
"link:"/books/IT"
},
...
]
}
现在 JS 不必知道如何连接 URLS。相反,它必须有逻辑表明您可以通过遵循集合表示中的 "link" URL 来获取书籍资源。这更复杂还是更不复杂?大致相同。关键区别在于,使用这种方法,客户端状态由超媒体驱动,基于媒体类型的约定语义。一旦确定并标准化了媒体类型及其处理规则,就可以在多个 API 中重复使用。