API - 多个请求与分离用户角色

时间:2014-07-31 15:04:59

标签: api rest single-page-application

我正在处理单页应用程序的前端,我必须列出一些学生。每个学生都附加到某个user_id这是我执行GET /students时所有用户角色(superadmin,admin,教授,学生)返回的API:

{
  address: null
  class_id: 184
  class_name: "I B"
  date_of_birth: null
  first_name: "first"
  gender: null
  grade: 1
  id: 192
  last_name: "last"
  nationality: null
  place_of_birth: null
  ranking_by_class: 0
  ranking_by_school: 0
  registration_number: null
  user_id: 238
}

我正在研究superadmin角色,因为我需要每个学生的额外数据(subscription_type),这只能在GET /users/:id上找到

因此,当我通过GET /students/在页面上列出20-30名学生时,为了获得subscription_type,我还需要执行20-30个额外请求,每个请求一个学生。

我和API人谈过这件事,我被告知将额外的数据包含在students中并不是RESTful的做法“,”它会减慢响应时间“” “额外30个请求的重量不到一大块”。

我对API的工作一无所知,所以我真的没有发言权,但是我觉得在页面加载上有30个请求是荒谬的,我是不是很疯狂?

接下来是什么?我会继续执行额外的请求吗?他应该为每个用户角色分离响应,并且只包括每个角色所需的内容吗?处理此问题的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

虽然严格来说API人是正确的,但严格遵循RESTful福音会导致效率低下,例如纯粹实现所产生的1 + N问题。 RESTful设计中的一个关键概念是资源不必直接映射到域对象。在设计资源时,必须考虑使用场景。在超级管理员方案中,听起来就像客户端请求students的集合时,它通常或者总是需要来自users的数据,特别是subscription_type。对象模型显然应该按照原样进行标准化,但这并不是说资源必须是,或者必须始终是。

我使用了几种不同的模式来使类似的场景更有效。哪个(如果有的话)适用取决于客户端如何使用资源。

复合资源

这是将全部或部分两个或多个域对象(例如studentuser)组合到一个资源中。

由于所有students大概也是users,因此您可以根据需要在学生资源中包含全部或部分用户数据。

GET /students

{
  address: null
  class_id: 184
  class_name: "I B"
  date_of_birth: null
  first_name: "first"
  gender: null
  grade: 1
  id: 192
  last_name: "last"
  nationality: null
  place_of_birth: null
  ranking_by_class: 0
  ranking_by_school: 0
  registration_number: null
  user_id: 238
  subscription_type: "foo"
}

相关资源

(与另一个响应类似)这是一种技术,客户端可以指示它想要包含在响应中的相关资源。这在域模型中的“具有”类型关系时特别有用。它允许客户端基本上延迟加载急切加载资源。

GET /students

{
  address: null
  class_id: 184
  class_name: "I B"
  date_of_birth: null
  first_name: "first"
  gender: null
  grade: 1
  id: 192
  last_name: "last"
  nationality: null
  place_of_birth: null
  ranking_by_class: 0
  ranking_by_school: 0
  registration_number: null
  user_id: 238
}

GET /students?include_user=true

{
  address: null
  class_id: 184
  class_name: "I B"
  date_of_birth: null
  first_name: "first"
  gender: null
  grade: 1
  id: 192
  last_name: "last"
  nationality: null
  place_of_birth: null
  ranking_by_class: 0
  ranking_by_school: 0
  registration_number: null
  user_id: 238
  user:
  {
   id: 238
   subscription_type: "foo"
   ...
  }
}

答案 1 :(得分:0)

这里有两个问题,不应该捆绑在一起 - 一个是为索引调用(/学生)返回的每个用户的数据,另一个是应该确定某个用户可以接收哪些数据的授权过程。

关于数据问题 - 我认为没有具体的规则可循。这完全取决于您的应用程序的要求。如果通常不需要subscription_type字段,您可以考虑传递查询参数(例如'include_extra_data = 1')以指示您在特定请求中需要它,默认情况下不会返回。

关于授权问题 - 这应该与您在请求中提出的数据完全断开。服务器应该能够根据用户ID确定用户可以看到哪些数据。 (您可以查看CanCan gem][1]作为可能的解决方案。)

因此,结合这两个问题,任何类型的用户都应该能够在有或没有'include_extra_data'标志的情况下发出'/ students'请求。如果服务器发现用户未经授权查看额外数据,您可以选择以下两个选项之一 - 仅返回允许用户查看的数据,或返回“未经授权的401”响应。

这两种方式都有效,并影响您在客户端应用上处理响应的方式。 (我个人而言,更喜欢后者,因为它对客户来说更具描述性。)

希望这有帮助:)