我正在为RESTful API设计自定义媒体类型,并研究了一些"标准"链接关系的类型和语义含义,以使我的设计具有一定的引导性.
为了演示这个问题,让我说我有一个资源,我可以执行标准的读取,更改,删除方法,并分别使用GET,PUT和DELETE的HTTP惯用法来实现这些方法.
我可以合理地(重新)使用RFC5023中定义的"编辑"链接关系(来自IANA链接注册表),其中规定:
"..."edit"的值指定href属性的值是可编辑成员条目的IRI.当出现在atom:entry中时,href IRI可用于检索,更新和删除资源由该条目代表...."
通过这种方式,用户代理可以理解具有"编辑"关系的链接将允许资源为GET,PUT和DELETEd.
然而,这里存在的问题是,如果编辑资源状态使得资源现在仅支持GET和DELETE操作,则"编辑"关系不再精确.
为了保持我需要的精度i)选项A:指定仅支持GET&DELETE的另一个(复合)链接关系,或ii)选项B:为每个可能的状态转移指定单独的链接并使用适当的链接来指示允许的国家转移.后一种方法提供精确但似乎过于冗长.
或者,(选项C)我可以保持"编辑"关系并接受缺乏精确性,即链接将传达GET,PUT,DELETE语义,但尝试PUT的用户代理将遇到HTTP错误' 405 - 方法不允许'.但是,我对这种方法不满意,因为它意味着客户端不支持状态转换.
总之,问题是平衡链接关系的一般性和精确性的最明智的方法是什么?
在构建与RESTful(希望)API对话的Backbone.js SPA的过程中.我试图围绕资源设计API,使用超媒体将资源链接在一起.当我开始在Backbone中实现内容时,我开始意识到使用Backbone完成真正的超媒体可能不太适合.
主要问题是希望将路径预先声明的骨干路由器.使用良好的Hypermedia API,资源URI不应在客户端进行硬编码,以便灵活地添加新功能和(喘息)更改资源位置.
我正在尝试将客户端级页面资源与API级别的对象资源分离.有人尖叫,如果这是坚果.基本上,这意味着在我的骨干应用程序中定义到资源的路径(想想一个离散的页面),然后检索一个或多个API级资源.
这导致了一些有趣的问题:
这甚至是个好主意吗?我是否应该尽力在我的应用程序中重用API级资源URI,使路由为1对1.
在一系列导航过程中,页面刷新会发生什么.如果它们不相同,我如何知道API级资源的位置?
在我看来,RESTful设计强调发现而不是事先了解事物.我是否正确地假设这个?这是代码下载的全部内容吗?如果我朝着正确的方向前进,有人可以指点我进一步阅读.
大多数资源都是只读的,因此只使用GET动词,但我确实有一些使用POST/PUT的场景(DELETE确实不在这个特定客户端的域中,除了可能在之前中止命令它被完全放置了.
*我只想说我绝不是一个REST大师.我还在学习中,所以请随时告诉我,我已完全离开了基地.没有感情会受到伤害.
编辑:
我一直在考虑与SPA相关的代码下载.还有一些选择:
在动态加载的"API"资源或类似资源中定义资源URI(代码下载).这是一个例子:
// this object downloaded along with the application code, on a refresh
Framework.API.Resources = {
Tasks: {
uri: '/tasks',
rel: 'self'
},
Users: {
uri: '/users',
rel: 'self'
},
// ... etc
}
// then in a collection
var TaskCollection = Backbone.Collection.extend(
uri: Framework.API.Resources.Tasks.uri
// implementation details
);
Run Code Online (Sandbox Code Playgroud)使用"root"资源uri作为路线,在浏览资源时动态定义路线.我相信Backbone.Router.route可以实现这一点,但我不确定它是否可以在运行中进行.有没人试过这个?
您将如何对可以具有两种不同表示形式的资源进行建模。例如,一个表示可能很“瘦”,其大部分相关资源都可以通过链接访问。另一种表示形式可能是“胖”,其中嵌入了大多数相关资源。这个想法是,有些客户不介意打很多电话来浏览链接的资源,而另一些客户则想一次获取所有数据。
考虑与导演,演员等相关的电影资源。也许它的精简版仅具有电影标题,并且要获取导演,演员列表等的数据,必须通过发出其他请求。嵌入到它们的链接。也许胖版本包含了嵌套在里面的所有电影,包括导演的数据,各个演员的数据等。
一个应该如何建模?
我看到一些选择:
application/vnd.movie.thin+json和application/vnd.movie.fat+json。/movies/1?view=thin)。您如何看待这种API的正确方法?
在阅读有关HATEOAS /超媒体约束的内容时,我经常看到的一件事是资源应该具有某种类型的self/href.对此的论点是客户端不应该知道如何构造该特定资源的URL,例如用于更新资源.
例如
{
//instead of "id":"123"
"href":"/api/v1/orders/123",
order state...
}
Run Code Online (Sandbox Code Playgroud)
我喜欢这个主意.
但是这个概念如何适合获取数据?假设我需要获取具有特定订单ID的订单,客户将如何处理该订单?在这种情况下,我仍然需要知道如何构造资源的URL,对吧?
客户端应该如何知道查找资源的位置和方式?它必须以某种方式了解API URL?
我正在使用spring-hateoas:0.18.0.RELEASE和spring-boot:1.2.5.RELEASE
为了调用我的 Web 服务并通过HAL链接,我使用Traverson 客户端 (客户端服务遍历的 API,受 Traverson JavaScript 库启发)
使用Hypermedia和HateoasRest的新功能
我的问题是什么时候需要使用PagedResources和Resource?
我在这里找到的示例 Traverson 客户端示例:
final PagedResources<Resource<Customer>> resources = traverson
.follow("customers","search","findByFirstName")
.withTemplateParameters(parameters)
.toObject(new TypeReferences.PagedResourcesType<Resource<Customer>>(){});
Run Code Online (Sandbox Code Playgroud)
我写的代码是:
ParameterizedTypeReference<Resource<ProjectJSON>> resourceParameterizedTypeReference = new
ParameterizedTypeReference<Resource<ProjectJSON>>() {};
Resource<ProjectJSON> projectJSONResource = traverson
.follow("projects")
.follow("$._embedded.projects[0]._links.self.href")
.toObject(resourceParameterizedTypeReference);
Run Code Online (Sandbox Code Playgroud)
我知道这不是一回事,但是在调用Traverson.toObject()方法时,资源的最佳实践是什么?
在RESTful Web API一书中,作者建议公开一个配置文件并使用一种确认链接关系的内容类型.Hydra扩展的JSON-LD似乎符合这些要求,我想在我的新API设计中使用它们.
我目前遇到性能问题.假设我有一个在线自行车商店,我想要检索有关给定自行车车轮的信息.
根据Hydra规范,在我看来,我需要发送2个请求来获取有关车轮的详细信息.第一个要求是自行车本身:
GET /mybike HTTP/1.1
Host: wowbike.com
Run Code Online (Sandbox Code Playgroud)
响应包含一个Hydra :: Link到轮子集合:
HTTP/1.1 200 OK
Content-Type: application/ld+json
{
"@context" :
{
"Bike": "/contexts/vocab#Bike"
},
"@id" : "/mybike",
"@type" : "Bike",
"size" : "L",
"wheels" : "/mybike/wheels" // "wheels" is a "hydra:Link"
}
Run Code Online (Sandbox Code Playgroud)
现在我可以向wheel资源发送第二个请求以获取详细信息:
GET /mybike/wheels HTTP/1.1
Host: wowbike.com
HTTP/1.1 200 OK
Content-Type: application/ld+json
{
"@context":
{
"Collection": "http://www.w3.org/ns/hydra/core#Collection",
"Wheel" : "/contexts/vocab#Wheel"
},
"@type" : "Collection",
"@id" : "/mybike/wheels",
"member" :
[
{
"@id" : "/mybike/wheels/firstwheel", …Run Code Online (Sandbox Code Playgroud) 我试图围绕如何(以及是否要)在我的api中实现HATEOAS进行研究。我喜欢这样一种概念:仅向客户提供在当前情况下适当的操作。但是我不确定我是否正确实现了这个想法。
假设我有一个资源类型订单,其状态可以更改,它可以具有不同的状态(处理中,接受,拒绝,过期,成功)。然后,我应该创建以下json对象:
{
...
"links": {
"accept": "http://example.com/order/1/accept",
"decline": "http://example.com/order/1/decline"
}
}
Run Code Online (Sandbox Code Playgroud)
还是我在这里创建不必要的动作?如果以上正确,是否应通过PATCH或GET更改状态?如果是PATCH,一个人怎么会知道(打败了超媒体的目的)?
编辑:忘记添加订单ID
According to the HAL standard (see here and here) the links to other resources should be placed in a specific embedded section.
So for instance this is not valid HAL, is my understanding correct?
{
"movies": [
{
"id": "123",
"title": "Movie title 1",
"_links": {
"subtitles": {
"href": "/movies/123/subtitles"
}
}
},{
"id": "456",
"title": "Movie title 2",
"_links": {
"subtitles": {
"href": "/movies/456/subtitles"
}
}
}
],
"_links": {
"self": {
"href": "/movies"
}
}
}
Run Code Online (Sandbox Code Playgroud)
The …
hypermedia ×8
rest ×7
hateoas ×6
api ×1
api-design ×1
backbone.js ×1
hal ×1
http ×1
hydra-core ×1
json ×1
json-api ×1
json-ld ×1