当前位置: 首页 > 面试题库 >

HAL-如果链接位于主体中,是否违反HAL格式/标准?

公沈浪
2023-03-14
问题内容

根据 HAL标准
(请参阅此处和此处),与其他资源的链接应放在特定的嵌入式部分中。

因此,例如这不是有效的HAL,我的理解正确吗?

{
  "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"
      }
   }
}

上述JSON无效的原因是,链接应放在链接到主体ID 的嵌入部分( “ _embedded” )中。因此正确的方法是:

   {
      "movies": [
         {
           "id": "123",
           "title": "Movie title 1",
         },{
           "id": "456",
           "title": "Movie title 2",
         }
      ],
      "_embedded": {
          "movies": [
             {
               "id": "123",
               "_links": {
                 "href": "movies/123/subtitles"
               }
             },
             {
               "id": "456",
               "_links": {
                 "href": "movies/456/subtitles"
               }
             }
          ]
      }
      "_links": {
          "self": {
             "href": "/movies"
          }
       }
    }

以上所有正确吗?

谢谢


问题答案:

将用它作为用hal重新设计的案例研究。@darrel millers的回答是好的,但不是很好,我认为有些事情应该清除。这将是漫长的。

The big question is what is the context…IE what is this resource you are
returning. All you’ve got is something that relates to movies somehow. Like
suppose this is a search result…having a movie relationship is the wrong
approach..as the movie relates to the search result “top level resource” as an
item. so it should be something more like

{
   title : "Results for search XXXXX"
   _links : {
      self : { href: "https://host.com/search/with/params/XXXXX"},
      item : [
         { href : "https://host.com/url/to/movie/result/one", title : "A great Movie"},
         { href : "https://host.com/url/to/movie/result/two",  title : "A Terrible Movie"},
      ]

   }  
}

但是这种结构对于客户端要构建一个UI来说是昂贵的,因为它将不得不进行3次调用。.遵循N +
1规则(结果集为1。然后每个结果为N),因此诞生了_embedded只是超文本预取模式的半个实现(在http2中,服务器实际上可以发送每个结果,因为它是其自己的文档,并且客户端的缓存中将预先填充这些结果,因此您不一定需要_embedded)。该结构看起来像这样:

{
   title : "Results for search XXXXX"
   _links : {
      self : { href: "https://host.com/search/with/params/XXXXX"},
      item : [
         { href : "https://host.com/url/to/movie/result/one", title : "A great Movie"},
         { href : "https://host.com/url/to/movie/result/two",  title : "A Terrible Movie"},
      ]

   },
   _embedded : {
     item : [
       {
         _links : {
           profile : {href : "https://host.com/result-movie"},
           canonical : {href : "https://host.com/url/to/movie/result/one"}
         },
         title : "a great movie",
         rating : "PG",

       },
       {
         _links : {
           profile : {href : "https://host.com/result-movie"},
           canonical : {href : "https://host.com/url/to/movie/result/two"}
         },
         title : "a terrbile movie"
         rating : "G",
       }
     ]
   }

}

1个HTTP请求获得3个资源真是太好了。1个请求不是N + 1。谢谢哈尔!

那为什么要买东西呢?搜索结果很好,仅包含电影…这是非常不可能的..即使今天也如此…您是否希望它明天仅包含电影…那是非常狭窄的,并且此结构是您的合同必须永远保持。但是您的UI确实希望将结果显示为电影。我添加的配置文件链接用于…客户端使用该配置文件链接来了解其当前正在处理的资源..以及可用于构建UI的字段。一个体面的客户端在处理集合时会显示它可以配置的内容,而忽略不了的配置文件(可能会记录警告)。由客户开发人员升级他们的应用程序以支持新的配置文件…不相信我吗?考虑一下网络浏览器如何解析html无法理解的标签…<thing- not-invented-yet></think-not-invented-yet>在您的html文档中,看看一个好的客户是如何工作的。

您应该注意的另一件事是,我不使用自我链接而是规范的。多年来,我改变了对此的立场。到目前为止,我默认使用规范,并且仅在维护目标资源的版本时才使用self,将嵌入式对象链接到所嵌入的特定版本非常重要。根据我的经验,这非常罕见。我告诉客户跟随它的存在,或者在导航到嵌入项时遵循规范。这样,服务器就可以完全控制将客户端移至何处。顶级资源,在这种情况下,结果应该仍然具有自我…在这种情况下,这是有意义的,因为随机搜索可能没有规范的链接…除非它是非常普通的关键字搜索…然后它可能应该与其他用户可以使用相同的网址。

让我们花点时间讨论一下为什么item会如此,因为这真的很重要。由于这是一个搜索结果。.为什么没有rel是result。有一个非常简单的答案..
result不是IANA链接注册表的成员https://www.iana.org/assignments/link-relations/link-
relations.xhtml,因此result完全无效…现在您可以“命名空间”您的扩展名依赖于my:resultour:result(“命名空间”由您决定,这些仅是示例),但是,如果IANA注册中心中已经存在一个非常好的扩展名,那么为什么还要为此烦恼item

让我们谈谈itemsvs item(或x:moviesvs
x:movie)。好吧items,IANA也没有。.so一定x:items要这样做,但让我们考虑一下原因。如果我们的结果文档以HTML表示,则将是这样的(忽略我缺少的身体头部等,为了简洁起见,格式不正确):

<html>
  <title>Results for search XXXXX</title>
  <a rel="item" href="https://host.com/url/to/movie/result/one" >A Great Movie</a>
  <a rel="item" href="https://host.com/url/to/movie/result/two" >A Great Movie</a>
</html>

这是第一个示例的SAME资源(不嵌入子资源)。只是表示为text/html和不是application/hal+json。如果我在这里迷路了(这是大多数人真正感到困惑的地方,那么我能提供的最好的办法就是在

HAL有一个陷阱,将其像JSON一样对待,并导致产生类似于movies机器可读或更好的注释的语句。让我通过在用例中继续此HTML表示来解释这是如何实现的。当客户解析此文档以查找item链接时,它必须解析EVERY
a标签并仅过滤到rel="item"存在属性的那些标签。那是“全表扫描”
..我们如何摆脱这些?我们创建一个索引。JSON具有在其结构中内置索引的概念。这是带有数组值的键。 index : [ {entry 1}, {entry 2} ]。HAL的作者知道通过链接获取链接(在_links或_embedded中的预取链接)的最常见方法是。因此,他构造了自己的规范,以便对rel进行索引。所以当你看到:

   _links : {
      self : { href: "https://host.com/search/with/params/XXXXX"},
      item : [
         { href : "https://host.com/url/to/movie/result/one", title : "A great Movie"},
         { href : "https://host.com/url/to/movie/result/two",  title : "A Terrible Movie"},
      ]

   },

知道这是真的

   _links : {
      self : { rel: "self", href: "https://host.com/search/with/params/XXXXX"},
      item : [
         { rel:"item", href : "https://host.com/url/to/movie/result/one", title : "A great Movie"},
         { rel:"item", href : "https://host.com/url/to/movie/result/two",  title : "A Terrible Movie"},
      ]

   },

因为rel是链接对象而不是资源的属性。但是http上的字节很昂贵(gzip会摆脱它),并且开发人员不喜欢冗余(整个主题),所以当我们暂停时,由于HAL结构已经使rel变得明显,所以我们忽略了rel属性。虽然当解析器遇到以下情况时并不太明显:

{ href : "https://host.com/url/to/movie/result/one", title : "A great Movie"}

有什么关系?您必须将其从父节点传递进来。这总是很丑的……无论如何,这一切都表明在HAL中通常消除了冗余。一旦消除了这种冗余,就很容易将索引键更改为复数形式,items但是知道那意味着您说的是您的链接(一旦冗余将{rel: "items", href : "https://host.com/url/to/movie/result/one", title : "A great Movie"}回退),那显然是错误的。该链接并不适用于许多项目。 ..只有一个。

因此,在这种情况下消除冗余可能不是最好的..但这是有好处的,HAL遵循_links和_embedded的模式,这就是我们要对搜索结果进行的处理..鉴于所有item链接都没有预取并且以_embedded形式存在,将它们保留在_links中并不重要。因此,它应如下所示:

{
   title : "Results for search XXXXX"
   _links : {
      self : { href: "https://host.com/search/with/params/XXXXX"}
   },
   _embedded : {
     item : [
       {
         _links : {
           profile : {href : "https://host.com/result-movie"},
           canonical : {href : "https://host.com/url/to/movie/result/one"}
         },
         title : "a great movie",
         rating : "PG",

       },
       {
         _links : {
           profile : {href : "https://host.com/result-movie"},
           canonical : {href : "https://host.com/url/to/movie/result/two"}
         },
         title : "a terrbile movie"
         rating : "G",
       }
     ]
   }

}

现在,我们有一个不错的搜索结果,其中包含2部电影(并且将来可以包含更多内容而不会违反合同)。注意:如果您以前只是使用_links而没有_embedded
…,则无法删除_links,因为那里的某些客户端取决于它们的存在..因此,最好尽早考虑这些内容…当使用资源的HAL表示形式时,行为举止客户端应始终在_links之前检查_embedded
…因此,真正由您决定所有客户端是否行为良好。

好的,让我们转到一个x:movie正确的关系..如果顶级资源是一个参与者的情况下,那可能会很好。所以像这样:

{
   Name : "Paul Bettany"
   _links : {
      canonical : { href: "https://host.com/paul-bettany"},
      "x:movie" : [
         { href : "https://host.com/url/to/movie/result/one", title : "A great Movie"},
         { href : "https://host.com/url/to/movie/result/two",  title : "A Terrible Movie"},
      ],
      "x:spouse" : { href: "", title: "Jennifer Connely"}
   },
   _embedded : {
     "x:movie" : [
       {
         _links : {
           profile : {href : "https://host.com/result-movie"},
           canonical : {href : "https://host.com/url/to/movie/result/one"}
         },
         title : "a great movie",
         rating : "PG",

       },
       {
         _links : {
           profile : {href : "https://host.com/result-movie"},
           canonical : {href : "https://host.com/url/to/movie/result/two"}
         },
         title : "a terrbile movie"
         rating : "G",
       }
     ]
   }

}

注意:我在顶层使用了canoncial而不是self,因为actor是长期存在的资源。该actor将一直存在。而且actor没有版本化。为了完整起见,我在_links和_embedded中都保留了x:movie,但是实际上我在_item中没有。我还将它们保留在_links中,以显示使用x:movie的原因,以便您可以将其与x:spouse区别开来(语义区别在我们开始的搜索结果中没有意义)。最后,这是需要注意的有用,我嵌入式x:movie但不是x:spouse这只是为了说明,这是不是一个非此即彼/或事物。您可以预取/嵌入用例所需的链接。实际上,我经常根据客户端的身份嵌入内容。即,我知道iOS可以显示android无法显示的内容。

除了那些注释,我到这里来的原因是我想弄清楚您不应该也不应该拥有该电影:您拥有的数据字段…仅依赖于_embedded中的电影数据。您说过soemthign就像将电影中的值与_links或_embedded中的值进行匹配…您不应该那样做..这没有任何意义。电影是资源…使用电影的链接资源而不是某些数据字段。您需要尽早决定什么是资源和什么是数据。我最好的建议是,如果事物具有链接关系,那么这就是资源。在我的演讲中,我将使用更广泛的术语(超媒体控件)来进一步了解这一点,而我现在还不想进入这里。

最后的说明..在超媒体应用程序中,您知道如果暴露内部ID字段,则您做错了。那应该是一个巨大的危险信号,表明有问题。您描述的ID的用例是将数据字段影片与_embedded
x:movie匹配。如前所述…您不应该那样做。并且id字段的出现应该使您陷入这种不良做法。

我被要求在这里回答..所以我希望这会有所帮助。



 类似资料:
  • hal

    hal A runtime environment for Haskell applications running on AWS Lambda. Flexible This library uniquely supports different types of AWS Lambda Handlers for your needs/comfort with advanced Haskell.In

  • Spring Data Rest到底应该如何配置以返回普通JSON而不是HAL(带有超媒体链接的JSON) null

  • 在Android NDK项目中,我们需要使用HAL接口访问蓝牙。我们的意图是这样做: 每个人似乎都这么做(在谷歌示例代码中)。当我们试图编译时,似乎出现了一个问题: 我们在Android.mk中正确添加了清单权限和正确添加的库 我们还需要补充什么吗?有没有可以参考的工作项目?

  • 我跟着Spring走。io是一个关键的教程,可以让REST API与MySQL DB一起启动,一切都进展顺利。然而,我发现了一个我无法配置或解决的行为。 当我使用内置功能从PagingAndSortingRepository中检索资源时,生成的剩余资源会自动分页,并用有用的HAL链接(链接、self、搜索、链接资源等)进行封装。我想用这个。 当我实现我的控制器来定制PostMapping行为并引入

  • 来自Liskov替代原理-www.blackwasp。co.uk 不符合LSP的一个常见指示是当客户端类检查其依赖项的类型时。这可以通过读取人为描述其类型的对象的属性或通过使用反射来获得类型。通常,根据依赖项的类型,将使用开关语句执行不同的操作。这种额外的复杂性也违反了打开/关闭原则(OCP),因为随着更多子类的引入,客户端类需要修改。 以下技术(使用反射)是否会导致违反LSP? 依赖注入 注:我