在REST架构中,客户端如何使用Hypermedia?

时间:2014-07-03 15:54:22

标签: rest restful-architecture

在学习REST架构时,我注意到Hypermedia似乎是统一接口约束的一个重要部分,可以成为RESTful;但是,我很难理解如何根据网络上发现的超媒体定义,客户端如何使用这种超媒体概念。

根据我对REST的理解,超媒体基本上是在包含资源表示的休息响应中提供给客户端的链接(因此客户端只需知道基本入口点的URL到REST服务)。这些链接基本上是为了帮助客户知道它收到的表示有哪些选项(例如,如果我请求/ children / resource,我可能会收到一个包含/ children / youstst链接的xml子列表, / children / oldest /,children / create等...这正是我很难理解的...为什么服务器必须将这些“超媒体”链接返回给客户端?客户端不应该已经知道这些链接?客户端不会自己阅读链接并正确地遵循它们......有人必须事先编写客户端代码(例如html和/或javascript)。这些链接对于客户如果客户应该已经了解它们?我缺少什么?

5 个答案:

答案 0 :(得分:1)

考虑如何浏览网页。 REST非常相似(尽管您实际上是在描述相关主题HATEOAS)。目的是您的客户端将检索初始数据,然后通过某种方式决定是否请求引用的数据。在浏览器中,会立即请求某些引用(例如css,javascript,images),而其他引用(例如href)只会显示给用户,并且只有在用户选择单击链接时才会检索。您的REST客户端也是如此 - 您将根据自己的要求自行决定哪些引用自动请求,以及向用户显示哪些决策。

如果您有一个显示某人的应用程序及其地址,那么您的应用程序将被编写为自动在人员数据中​​找到地址引用并检索它。如果您的应用程序显示某人并显示相关数据的选项,那么您将向该人显示允许用户选择检索和显示地址数据的超链接(或类似内容)。

当您考虑客户端如何直观地表示其检索的信息时,问题就出现了。为此,REST样式建议您应该允许服务器返回javascript以动态解析新数据(例如,上面示例中的地址)。也许返回的数据也包含类似css的引用,这将有所帮助。也许它会包含允许动态用户交互的javascript链接(这对我来说听起来很危险,但它到底是什么,它适用于网络)。

答案 1 :(得分:1)

超媒体确实是创建RESTful接口的重要部分。但是,我看到一个完整的超媒体客户端(sometimes referred to as HATEOAS)只是变得更加RESTful的一个点。 Richardson Maturity Model描述了变得更加RESTful的3个步骤,并且在考虑在特定项目中采用多少RESTful模式时,我发现这些是很好的指导。

IMO,完整超媒体客户端的最佳示例是Web浏览器。 Web浏览器了解html <a href>标记表示链接。链接的关键是用户可以在他们的旅程中发现功能。因此,在设计RESTful API时,可以应用相同的原则。

  

为什么服务器必须返回这些&#34;超媒体&#34;链接到   客户端?

因此,一个原因是客户端(如果编写为公开链接)可以允许状态转换被发现。

使用链接的另一个好处是您的API负责每个链接的结构和数据。因此,服务器端API正在为每个请求生成链接。这意味着服务器API可以在不破坏客户端的情况下对链接进行更改(版本或结构)。

您可以构建没有链接的RESTful API(Richardson Level 2),但是如果您想更改其中一个API请求的URL,该怎么办?您需要实现版本控制策略(通过URL或标头),或者您需要为新功能创建新的URL。随着时间的推移,这可能会失控。

答案 2 :(得分:1)

Fielding定义了统一接口约束,以便将客户端与服务的实现分离。这与在任何oo语言中定义新接口相同。您可以定义它以将类与其依赖项的实现分离。

要将客户端与URI结构分离,您需要响应中的链接,其中包含语义注释和URI。因此,您的客户可以根据语义标注(例如link relationa term in a related RDF vocab)决定要关注的链接。这样就不需要了解任何有关URI结构的信息。

您需要将客户端与服务的实现细节分离,以使其可重用。最后,您可以像今天的Web浏览器一样创建一般客户端。这些客户了解他们所做的事情的区别在于,他们不必依赖人类。

答案 3 :(得分:0)

  

如果客户应该已经知道这些链接对客户有什么好处?

它们使状态转换更直接地成为接口的一部分。它们告诉客户端在当前状态下是否可以使用这些链接或状态转换(如果不存在,则不可用!)。

如果客户端没有注意到这一点,则它可能仍会尝试生成并遵循实际上不可用的选项(状态转换)的URL。可能有必要复制逻辑以确定双方在特定状态下可能发生的事情,以确保避免这种情况。

如果尝试进行无效的链接/状态转换,则服务器应报告错误。

另一方面,如果客户端从不允许生成/跟随服务器未提供的链接,则客户端可能具有意识并提早提供有关该问题的反馈(通常会导致更清晰的情况或错误消息),并且服务器应该正确处理无效的请求,以防万一不是这样,这将不是一个大问题,因为它一开始就不太可能发生。

答案 4 :(得分:0)

Something like this.

        var discountDetails = new AddDiscountForm()
        {
            promotionId = 123456,
            discountType = "Promotion",
            discount = UnitValue.FromFloat(14.00)
        };

        await journey
            .SelectRoot()
            .SelectRelation("product-finder", new { barcode = "23409-23097" })
            .SelectItem(0)
            .SelectRelation("add-discount", discountDetails)
            .RunAsync();

In fact I took the idea from my response and built it.

https://github.com/lukepuplett/surfdude-csharp