Rest HATEOAS-发现和URI模板

Rest HATEOAS-发现和URI模板,rest,discovery,hateoas,Rest,Discovery,Hateoas,我正在为公司内部数据设计一个HATEOAS API,但在发现链接方面遇到了麻烦。考虑以下步骤:有人检索该系统中特定雇员的信息: 用户发送GET到http://coredata/要获取所有可用资源,返回多个链接,包括标记为rel=“http://coredata/rels/employees” 用户在第一个请求的rel上跟随HREF,执行GET at(例如)http://coredata/employees 最后一次通话返回的数据是我的难题,在这种情况下,我听到了各种不同的建议。以下是其中一些:

我正在为公司内部数据设计一个HATEOAS API,但在发现链接方面遇到了麻烦。考虑以下步骤:有人检索该系统中特定雇员的信息:

  • 用户发送GET到
    http://coredata/
    要获取所有可用资源,返回多个链接,包括标记为rel=“
    http://coredata/rels/employees
  • 用户在第一个请求的rel上跟随HREF,执行GET at(例如)
    http://coredata/employees
  • 最后一次通话返回的数据是我的难题,在这种情况下,我听到了各种不同的建议。以下是其中一些:

  • 该GET将返回所有员工(可能包含截断的数据),客户机将负责从该列表中选择所需的员工
  • 该GET将返回大量URI模板链接,描述如何查询/获取一名员工/获取所有员工。比如:

  • 我有点被困在这里,和HATEOAS最接近。对于选项1,我确实不想让我的客户每次都检索所有员工以便于导航,但我可以看到在示例2中使用URI模板是如何引入一些带外知识的

    我的另一个想法是使用RetrieveOne、Query和所有操作作为我的酷URL,但这似乎违反了您应该能够从一个基本URI导航到所需资源的概念


    还有谁能想出一个好办法来处理这个问题吗?一旦您检索到一个或一组资源,导航就非常简单,但它似乎很难用于发现。

    我的HATEOAS API返回HTML以及您正在使用的,并且它们都使用相同的URI,因此我的JSON响应只返回人类web用户将看到的内容(减去所有漂亮的颜色)。e、 g


    选项2并不太糟糕,因为您正在使用它来描述URI模式;虽然HATEOAS通常是以不让客户机合成URI的方式表述的,但如果服务器准备对URI模板做出保证,并以标准格式显式地告诉客户机,那么这是可以接受的。(我很想让“列出所有员工”URL不带
    all
    后缀,以便将其与具有该ID的员工区分开来;原则上,客户不应该知道员工ID是什么样子。)


    事实上,主要问题实际上是客户机必须理解这些标记URI的含义;没有真正的方法来猜测“
    http://coredata/rels/employees#All
    “是指“列出所有员工”。这就是你在客户机中嵌入知识、语义标记等的地方,而HATEOAS并没有真正解决这些问题。

    TL;DR:使用选项方法以编程方式返回可使用的文档,并始终实现分页。

    我们在我的工作中创建了许多内部REST服务。我们已经对使用OPTIONS方法返回资源元数据进行了标准化。我们返回的元数据充当该资源的可解析文档。它指示url模板、各种选项(如页面、页面大小)以及资源支持的不同方法。我们还返回rel链接,这样就可以使用选项进行顶级资源发现,而无需拉取和实际数据


    我们还专门实现分页,以防止不必要地返回大量数据时出现问题。

    我喜欢这种方法的想法&许多人都尝试过实现一些东西。例如
    "_links": {
        "http://coredata/rels/employees#RetrieveOne": {
            "href": "http://coredata/employees/{id}"
        },
        "http://coredata/rels/employees#Query": {
            "href": "http://coredata/employees{?login,firstName,lastName}"
        },
        "http://coredata/rels/employees#All": {
            "href": "http://coredata/employees/all"
        }
    }
    
    GET /
    
    
    {"_links": {
        "http://coredata/companies": { "href": "/companies?page=1" }
        ...
    }}
    
    
    
    GET /companies?page=1
    
    
    {"_links": {
        "next": { "href": "?page=2" }
        ...
    }}