【问题标题】:REST : Return complex nested data vs. multiple calls [closed]REST:返回复杂的嵌套数据与多次调用[关闭]
【发布时间】:2016-04-11 21:16:56
【问题描述】:

我有一个由 NodeJS 提供给 AngularJS 前端的 REST api。

我与users 合作:

GET  /api/users  #Returns all users
POST /api/users  #Create  new user

GET   /api/users/:id   #Return a user
PUT   /api/users/:id   #Edit a user
DELTE /api/users/:id   #Delete a user

这是一个用户:

{
  login : "admin"
  email : "admin@admin.com"
  pass  : "hashedpassword"
  ...
}

我的用户可以属于groups

GET   /api/users/:id/groups   #Return the groups of a user

他们也可以拥有constraints 或者可以从他们的组中继承constraints

GET   /api/users/:id/constraints   #Return the constraints of a user
GET   /api/groups/:id/constraints   #Return the constraints of a group

问题:

我正在制作一个管理页面,显示所有用户、他们的组、他们的约束。

我应该:

  1. 在 javascript (Angular) 前端的 for 循环中发出许多请求

类似:

$http.get(/api/users).then(function(result) {
  result.data.forEach(function(user) {
    $http.get('/api/users/'+user.data.id+'/groups).then(function(groups) {
      groups.forEach(function(group) {
        $http.get('/api/groups/'+group.data.id+'/constraints)
      })
    })
  })
})
  1. 创建路径/api/users/withConstraintsAndGroups

这将返回一个包含所有用户及其组和约束的大列表。


我发现解决方案 1 非常好、可维护、简单且通用,但我担心性能很差

我发现解决方案 2 丑陋、难以维护、难以编码、不通用但性能良好

我应该选择哪种解决方案?

【问题讨论】:

  • 您已经确定了每种方法的优缺点。你现在必须做出决定。征求我们的意见是题外话。

标签: javascript angularjs node.js api rest


【解决方案1】:

你的问题基本上可以归结为:

哪个更好,一个大的 HTTP 请求,还是多个小的 HTTP 请求?

要记住的一件事是客户端和服务器之间的预期网络延迟(ping 时间)。在具有良好带宽的高延迟情况下,许多小请求的性能将明显比一个大请求。

此外,拥有一个大请求可以提高compressing the response 的效率,并避免extra HTTP requests and response headers 的开销。

说了这么多,我仍然建议你选项1开始,仅仅因为你说你很容易编码。然后看看它是否符合你的要求。如果没有,那么尝试选项 2

最后一点,我通常更喜欢一个大请求而不是许多小请求,因为这样可以很容易地将每个请求定义为一个完全应用或回滚的事务。这样一来,我的客户就不会遇到这样一种状态,即他们的许多小请求中的一些成功,而另一些则失败,并且他们现在拥有我的 API 提供的数据的本地副本不一致。

【讨论】:

    【解决方案2】:

    来吧,根据结果将几乎相同的论点,多个请求与一个海量请求,它的性能成本是多少。我们在 2016 年,除非您正在处理糟糕的互联网连接,否则您应该通过发出多个请求来做到这一点。

    您正在为全球 99% 的人口或 1% 的使用 Opera 的部分开发应用程序(用于 turbo 功能)?

    另外,如果我们谈论的是设计一个REST api,那么一致可能是这种 API 的主要思想。在您的情况下,如果您编写第二种方法,则必须在其余代码中编写类似的内容以保持所有控制器的一致性,这是无法做到的。

    Also, an API is an API and should not be modified when a front end application is being built on that API. 想一想当您有 10 个应用程序请求您的 API,但您处于与您提出的相同情况的情况下,但您需要为每个应用程序提供不同的响应。您要向 API 添加新方法吗?这是一种不好的做法

    REST api 中的路由应根据您拥有的逻辑资源(可以使用 HTTP 动词操作的对象)进行:

    例子:

     * when you have a relation between entities
    
         /users/3/accounts       // should return a list of accounts from user 3
         /users/3/accounts/2     // should return account 2 from user 3
    
     * custom actions on your logical resources
    
        /users/3/approve
        /accounts/2/disable
    

    另外,一个好的 API 应该能够提供 partial requests(例如,向一个普通请求添加一些查询字符串参数:users/3?fields=Name,FirstName)、versioningdocumentation(在这种情况下 apiDocs.js 非常有用) , 相同的请求类型 (json), pagination, token authcompression (最后一个我没做过:))

    【讨论】:

    • HTTP verbs...你的意思是CRUD
    • 您好! HTTP 动词是指 HTTP 方法:GET、POST.. 等等。很抱歉将它们称为 HTTP 动词
    【解决方案3】:

    我建议修改您的端点以提供用户资源以接受(通过查询参数)应包含哪些关联资源作为响应的一部分:

    /api/users?includes=groups&includes=constraints
    

    这是一个非常灵活的解决方案,如果您的需求在未来扩展,您可以轻松支持更多相关资源。

    如果您担心如何构建响应,我建议您查看JSON:API

    使用JSON:API 的一个优点是,如果多个用户共享相同的组/约束,那么您将不必获取同一实体的多个表示。

    【讨论】:

      【解决方案4】:

      你在问

      哪个更好...

      根据 SO 规则这是不可接受的,所以我假设您的问题在于 REST 在某些情况下应该做什么。

      REST 基于资源,它们本身就像具有自己的数据和“访问器/获取器”的对象

      当您请求/api/users/:id/groups 时,您是在告诉您要从users 资源/表访问具有id 的特定用户,以及从该用户访问@ 列表987654324@他/她属于(或拥有,或您想要的任何解释)。在任何情况下,查询对于这个 groups 资源都是非常具体的(在 REST 术语中,它是唯一的,因为每个资源都可以通过它的 URL 进行通用定向)并且不应该“冲突”或被误解为另一个资源。如果 URL 可以定位多个对象(例如,如果您只调用 /api/groups),那么您的资源就是一个数组。

      考虑到这一点,我会考虑(并建议)始终返回与您指定的用例匹配的最大选择。例如,如果我要创建那个 API,我可能会这样做:

      /users所有用户列表

      /users/:id 特定用户

      /users/:id/groups特定用户加入的群组

      /users/groups 至少有一个用户的所有组的列表

      /users/groups/:id 来自/users/groups 的特定组的描述(详细)

      等等……

      每个用户案例都应该完全由 URL 定义。如果不是,那么您的 REST 规范可能(我几乎可以肯定)是错误的。

      ===========

      所以,回答你的问题,考虑到那个描述,我想说你的答案是:这取决于你需要做什么。

      如果您想在主页中显示每一个约束(可能,但不太优雅/废话 UI),那么是的,第一种方法很好(希望您的最终用户不要杀死您)。

      如果您只想按需请求资源(例如,在鼠标悬停时弹出信息或转到管理站点中的特定部分后),那么您的解决方案是类似于第二个(是的,这是一个很大的...只有当您真的需要该资源时,您才应该使用它)。

      你考虑过/api/users/:id/constraints按需路径吗?

      顺便说一句,withConstraintsAndGroups 不是 REST 资源。 REST 资源是名词(constraintsgroups,但不能同时使用两者)。不是动词或形容词。

      【讨论】:

        【解决方案5】:

        在我看来,管理页面的性能并不是什么大问题。两者之间的唯一区别是,在 #1 中有 3 个 api 调用,而 #2 只有一个。数据应该是一样的,数据应该是合理的,不是特别庞大的。因此,如果#1 更容易编码和维护,那么您应该使用它。您应该没有任何性能问题。

        【讨论】:

        • 在 #1 中,他有 3 次以上的通话。他正在为每个用户询问组。所以可能是数百个请求
        猜你喜欢
        • 2011-10-29
        • 2014-07-20
        • 2021-09-26
        • 1970-01-01
        • 1970-01-01
        • 2021-04-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多