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

时间:2016-01-07 13:02:25

标签: javascript angularjs node.js api rest

我有一个由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循环中发出多个请求?
  2. 类似的东西:

    $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
    2. 这将返回包含其组及其约束的所有用户的大列表。

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

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

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

5 个答案:

答案 0 :(得分:6)

您的问题基本归结为:

  

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

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

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

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

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

答案 1 :(得分:6)

来吧,在性能上花费多少,基于论文结果几乎相同,多个请求与一个大量请求相比。我们在2016年,除非您处理的互联网连接不佳,否则您应该通过提出多个请求来实现。

您正在为全球99%的人口或使用Opera的1%部分开发您的应用程序(用于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),paginationtoken authcompression(我从未做过最后一个:))

答案 2 :(得分:4)

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

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

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

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

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

答案 3 :(得分:1)

你问

  

哪个更好......

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

REST基于资源,它们本身就像对象一样拥有自己的数据和#34;访问者/获取者"。

当您要求/api/users/:id/groups时,您告诉您要从users资源/表格访问具有id的特定用户并且,从该用户,他/她所属的groups列表(或拥有,或任何你想要的解释)。在任何情况下,查询都非常特定于此资源(在REST术语中,它是唯一的,因为每个资源都可通过其URL进行通用指向),并且不应该" collision&#34 ;或被其他资源误解。如果可以使用URL定位多个对象(例如,如果只调用/api/groups),那么您的资源就是一个数组。

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

所有用户的

/users列表

/users/:id特定用户

特定用户已加入的

/users/:id/groups个群组

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

/users/groups/:id来自/users/groups(详情)

的特定群组的说明

等...

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

==========

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

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

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

您是否根据需要考虑了路径/api/users/:id/constraints

BTW,withConstraintsAndGroups不是REST资源。 REST资源是名词(constraintsgroups,但不是两者都有)。不是动词或形容词。

答案 4 :(得分:0)

我似乎并不认为管理页面的性能太重要了。几乎唯一的区别是,在#1中你有3个api调用,#2只有一个。数据应该相同,数据应该合理,不是非常巨大。因此,如果#1更易于编码和维护,那么您应该使用它。你不应该有任何性能问题。