我正在开发一个企业系统,它将在移动客户端和中央服务器之间使用RESTful Web服务.尽可能使用RESTful,让我们说.
我的问题涉及HATEOAS(超媒体作为应用程序状态的引擎),以及在HTTP响应主体中使用自定义xml.
该系统永远不会被公共客户端使用,但我喜欢HATEOAS的想法,即能够在以后修改服务器端资源分配模式,而无需独立地重新配置每个客户端.如果我们决定由于扩展问题我们需要在多个物理盒上扩展服务器功能,没问题,这将反映在客户端(或来自客户端的指令下的服务器)创建新资源时生成的URI中.
我们的业务领域非常具体和不寻常.因此,我想在整个Web服务中为HTTP响应实体主体使用自定义XML,并且客户端将从xml中解析资源URI,以便随时了解它在修改自己的应用程序状态时可以使用的资源位置.我知道这会"打破"HATEAOS的H部分.
例如,当客户端将事务发送到服务器进行处理时,服务器可能在201 HTTP响应主体中包含以下xml片段(作为更大的xml文档的一部分).服务器还会通知客户端新创建的事务资源本身的URI,但这可能只包含在Location HTTP头中.
<resulturi>http://resultserver/results/1234.xml</resulturi>
Run Code Online (Sandbox Code Playgroud)
这真糟糕吗?使用此服务的客户端几乎不可能基于浏览器.超媒体在xml中以纯文本形式提供uris的其他优点是什么?
我想我可以去XHTML,但我们的移动平台上的解析器使用POX更有效率.
我在这里看了很多关于SO的讨论,观看了Jon Moore的演讲(其中解释了很多,顺便说一句),并阅读了Roy Fielding关于HATEOAS的博客文章,但在客户端设计方面,我仍然感到有点暗淡.
API问题
现在,我只是返回带有表单/锚点和定义列表的xhtml来表示资源.以下代码段详细说明了我如何布置表单/锚点/列表.
# anchors
<li class='docs_url/#resourcename'>
<a rel='self' href='resource location'></a>
</li>
# forms
<form action='action_url' method='whatever_method' class='???'></form>
# lists
<dl class='docs_url/#resourcename'>
<dt>property</dt>
<dd>value</dd>
</dl>
Run Code Online (Sandbox Code Playgroud)
我的问题主要是表格.在Jon的演讲中,他记录了诸如(add_location_form)等表单类型以及它们所需的输入.我没有很多资源,但我正在考虑抽象表单类型(添加,删除,更新等),并在文档中注意,(添加,更新)您必须发送目标资源的有效表示并删除,您必须发送标识符.
问题1:有了HATEOAS的概念,我们真的不应该让客户"发现"表单(通过对它们进行分类添加,删除,更新等)并只发送回我们给他们的所有数据吗?我在这里的真正问题(不是一个讨论)是否遵循良好做法?
客户问题
在HATEOAS之后,我们对可以发现的资源采取的行动如何影响客户端代码(api的消费者)及其ui.听起来很棒,按照这些原则,UI应该只显示可用的操作但是如何实现?
我目前的方法是将响应解析为xml和usin xpath,以查找客户端开发时已知的操作(记录的表单类,即添加,删除,更新),并显示ui控件(如果可用).
问题2:我的发现方式错了吗?或者就客户而言(知道表单类),这太过神奇吗?这不会假设客户端知道哪些操作可用于每个资源(这可能没问题,因为它是创建客户端的一种原因,对吗?)并且应该记录操作(表单类)到资源的映射,或只是记录表单类,并允许客户端(和客户端开发人员)研究和发现它们?
我知道我到处都是这个,但任何见解都非常感激.我会回答一个回复,回答这两个问题中的任何一个.谢谢!
我已经开始设计一个API,并决定让它符合REST/HATEOAS.API的切入点应该是什么?
这似乎是一个常见的,GET /但从我所读到的,它可能在逻辑上更有意义使用OPTIONS /,因为实际上没有/用于检索的资源.
我在这里给出了两个例子,使用JSON的HAL语法作为超媒体格式.
请求:
GET / HTTP/1.1
Host: example.com
Run Code Online (Sandbox Code Playgroud)
响应:
HTTP/1.1 200 OK
Date: …
Content-Type: application/json;charset=utf-8
Content-Length: 143
{
"_links": {
"self": {
"href": "/"
},
"penguins": {
"href": "/penguins"
}
}
}
Run Code Online (Sandbox Code Playgroud)
请求:
OPTIONS / HTTP/1.1
Host: example.com
Run Code Online (Sandbox Code Playgroud)
响应:
HTTP/1.1 200 OK
Date: …
Allow: OPTIONS
Content-Type: application/json;charset=utf-8
Content-Length: 143
{
"_links": {
"self": {
"href": "/"
},
"penguins": {
"href": "/penguins"
}
}
}
Run Code Online (Sandbox Code Playgroud) 我正在使用apiary创建一些API ,因此使用的语言是JSON.
我们假设我需要代表这个资源:
{
"id" : 9,
"name" : "test",
"customer_id" : 12,
"user_id" : 1,
"store_id" : 3,
"notes" : "Lorem ipsum example long text"
}
Run Code Online (Sandbox Code Playgroud)
难道是正确的根据ID引用其他资源(12,1,3),或者我应该指定这些资源的URL(即/customers/12,/users/1,/stores/3)?
我没有使用HATEOAS,我有点困惑.
我有一个有趣的问题.我的数据模型如下:
A型:
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class A {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
Run Code Online (Sandbox Code Playgroud)
B型:
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class B {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
Run Code Online (Sandbox Code Playgroud)
嵌入式C:
@Embeddable
@JsonIgnoreProperties(ignoreUnknown = true)
public class C {
@ManyToOne
private A a;
@ManyToOne
private B b;
}
Run Code Online (Sandbox Code Playgroud)
和D型:
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class D {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ElementCollection
@OrderColumn(name = "ORDER_INDEX")
@CollectionTable(
name = "d_c_join",
joinColumns = @JoinColumn(name …Run Code Online (Sandbox Code Playgroud) hateoas spring-data spring-data-jpa spring-data-rest spring-hateoas
我正在尝试将HATEOAS与Spring HATEOAS一起使用,并且需要使用Spring HATEOAS将enums作为REST API公开.
我尝试了三种方法如下:
@RestController
@RequestMapping(path = "/fruits")
public class FruitResourceController {
@RequestMapping(method = RequestMethod.GET)
public Fruit[] fruits() {
return Fruit.values();
}
// NOTE: The `produces` attribute is only for browsers.
@RequestMapping(path = "/with-resource", method = RequestMethod.GET,
produces = MediaTypes.HAL_JSON_VALUE)
public Resource<Fruit[]> fruitsWithResource() {
Resource<Fruit[]> resource = new Resource<Fruit[]>(Fruit.values());
Link selfLink = linkTo(methodOn(FruitResourceController.class).fruitsWithResource())
.withSelfRel();
resource.add(selfLink);
return resource;
}
// NOTE: The `produces` attribute is only for browsers.
@RequestMapping(path = "/with-resources", method = RequestMethod.GET,
produces = MediaTypes.HAL_JSON_VALUE)
public …Run Code Online (Sandbox Code Playgroud) 我正在考虑使用HATEOAS定义REST API 。特别是,我发现非常有趣的概念,即为给定资源指示当前可用的操作。
某些HATEOAS规范包含太多无法满足我需要的开销,因此我查看了HAL规范,因为我发现它非常简洁实用:
{
_links: {
self: { href: "/orders/523" },
warehouse: { href: "/warehouse/56" },
invoice: { href: "/invoices/873" }
},
currency: "USD",
status: "shipped",
total: 10.20
}
Run Code Online (Sandbox Code Playgroud)
但是,HAL中的链接仅包含相关资源的列表,但不包含对它们的可用操作。按照上面的示例,我现在是否可以取消订单,还是不能取消?一些HAL示例通过使用特定的URL进行取消来解决此问题,并仅在可能取消的情况下在响应中添加相应的链接:
"cancel": { "href": "/orders/523/cancel" }
Run Code Online (Sandbox Code Playgroud)
但这不是非常RESTful的。取消不是资源。取消是对资源的删除,即:
DELETE /orders/523
Run Code Online (Sandbox Code Playgroud)
有没有一种很好的方法可以用HAL表示这一点,还是应该使用其他HATEOAS规范?
我正在考虑返回带有与self相同的URL的“取消”链接,但是在这种情况下,客户端必须知道要取消操作,他们必须使用DELETE动词,而HATEOAS响应中并未对此进行详细描述。
self: { "href": "/orders/523" },
cancel: { "href": "/orders/523" }
Run Code Online (Sandbox Code Playgroud)
这是HATEOAS / HAL的推荐方法吗?我了解HAL没有任何“方法”参数,而我自己添加该参数将违反HAL规范。
我有一个使用HAteoas的Rest-Service,以前没有分页的工作.现在我正在制作可分页的Json.我用Spring-Hateoas的开箱即用功能做到了这一点.但现在我正在坚持消费它,我想它确实没有很好的记录,如果是的话.
我的JSON如下所示:
{
"_embedded": {
"vertragResourceList": [
{
"identifier": 728,
"auszubildender": "Rumm",
"beruf": "Landwirt/in",
"betrieb": "Mitterbauer Johann",
"betriebsNummer": "e12d0949-67ae-4134-9dc2-fb67758b6b16",
"zustaendigeStelle": "Irgendwo",
"beginn": 529887600000,
"status": "RECENT",
"fachrichtung": null,
"schwerpunkt": "Grünland oder Ackergras",
"ende": 623113200000,
"_links": {
"self": {
"href": "http://localhost:8080/bbsng-app-rest/vertrag/728"
}
}
},
{
"identifier": 803,
"auszubildender": "Gossen",
"beruf": "Landwirt/in",
"betrieb": "Beer Johann",
"betriebsNummer": "d5a20cb9-7273-4b75-85bd-f8e7d6a843c4",
"zustaendigeStelle": "Woanders",
"beginn": 278118000000,
"status": "RECENT",
"fachrichtung": null,
"schwerpunkt": "Ackerfutterbau",
"ende": 339116400000,
"_links": {
"self": {
"href": "http://localhost:8080/bbsng-app-rest/vertrag/803"
}
}
}
]
},
"page": {
"size": …Run Code Online (Sandbox Code Playgroud) 如果你有一个REST API是hypermedia-driven(HATEOAS),你可以很容易地通过包括或省略响应链接更改客户端的行为(_links).这使客户端能够完全忘记测试当前状态resource(可存在或不存在操作的链接)的操作权限.
此外,如果当前用户没有查看权限,您可以在响应中省略属性.
这样,授权完全在服务器上完成(并控制有资格执行/查看的操作和属性).
但是,如果我想拥有一个read-only房产怎么办?REST API如果属性存在于请求(_POST_OR _PUT_)中,则忽略该属性是没有问题的.它不会得到保存.但客户端如何区分写入和只读属性以向用户显示适当的控件(如禁用的输入字段HTML)?
目标是永远不会拥有client request用户的权限,而是拥有完全由资源驱动的权限client/frontend.
任何帮助是极大的赞赏 :-)
我已经搜索了几天关于如何实现包含 HATEOAS 链接 + 使用 Spring boot 和 JPA 分页(无 spring 数据休息)的 Spring REST API,如下随机示例:
\n{\n "_links": {\n "first": {\n "href": "http://localhost:8080/api/albums-list?page=0&size=2&sort=title,desc"\n },\n "prev": {\n "href": "http://localhost:8080/api/albums-list?page=0&size=2&sort=title,desc"\n },\n "self": {\n "href": "http://localhost:8080/api/albums-list?page=1&size=2&sort=title,desc"\n },\n "next": {\n "href": "http://localhost:8080/api/albums-list?page=2&size=2&sort=title,desc"\n },\n "last": {\n "href": "http://localhost:8080/api/albums-list?page=4&size=2&sort=title,desc"\n }\n },\n "page": {\n "size": 2,\n "totalElements": 10,\n "totalPages": 5,\n "number": 1\n },\n "_embedded": {\n "albums": [\n {\n "id": 7,\n "title": "Top Hits Vol 7",\n "description": "Top hits vol 7. description",\n "releaseDate": "10-03-1987",\n "actors": [\n {\n "id": …Run Code Online (Sandbox Code Playgroud) hateoas ×10
rest ×9
api ×2
api-design ×2
java ×2
json ×2
consumer ×1
entry-point ×1
hal-json ×1
hypermedia ×1
spring ×1
spring-data ×1
spring-mvc ×1
web-services ×1
xml ×1