Javascript REST:返回复杂嵌套数据与多个调用

Javascript REST:返回复杂嵌套数据与多个调用,javascript,angularjs,node.js,api,rest,Javascript,Angularjs,Node.js,Api,Rest,我有一个RESTAPI,由NodeJS提供给AngularJS 我与用户一起工作: 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 : "ad

我有一个RESTAPI,由NodeJS提供给AngularJS

我与
用户一起工作

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"
  ...
}
我的用户可以属于

GET   /api/users/:id/groups   #Return the groups of a user
它们还可以具有
约束
,或者可以从组中继承
约束

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

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

我应该:

  • 在javascript(角度)前端的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)
          })
        })
      })
    })
    
  • 创建路径
    /api/users/withConstraintsAndGroups
  • 这将返回一个包含所有用户及其组和约束的大列表


    我发现解决方案1非常好、可维护、简单且通用,但我对非常糟糕的性能感到震惊

    我发现解决方案2很难看,很难维护,很难编码,不是通用的,但性能很好


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

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

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

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

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

    此外,拥有一个大请求可以提高您的请求效率,并避免请求的开销

    尽管如此,我仍然建议您从选项1开始,因为您声明编写代码非常容易。然后看看它是否符合您的要求。如果没有,请尝试选项2


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

    我建议修改为用户资源提供服务的端点,以便(通过查询参数)接受响应中应包含哪些相关资源:

    /api/users?includes=groups&includes=constraints
    
    这是一个非常灵活的解决方案,如果您的需求在将来扩展,您可以轻松地支持更多相关资源

    如果您关心如何构建响应,我建议您查看

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

    哪一个更好

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

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

    当您请求
    /api/users/:id/groups
    时,您告诉我们您希望从
    用户
    资源/表访问具有
    id
    的特定用户,以及从该用户访问他/她所属(或拥有,或任何您想要的解释)的
    组列表。在任何情况下,查询都非常特定于这个资源(用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资源是名词(
    约束
    ,但不是两者都有)。不是动词或形容词。

    算了吧,根据这篇论文,结果将是一场灾难,这场演出要花多少钱
     * 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