我正在处理单页应用程序的前端,我必须列出一些学生。每个学生都附加到某个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个请求是荒谬的,我是不是很疯狂?
接下来是什么?我会继续执行额外的请求吗?他应该为每个用户角色分离响应,并且只包括每个角色所需的内容吗?处理此问题的正确方法是什么?
答案 0 :(得分:2)
虽然严格来说API人是正确的,但严格遵循RESTful福音会导致效率低下,例如纯粹实现所产生的1 + N问题。 RESTful设计中的一个关键概念是资源不必直接映射到域对象。在设计资源时,必须考虑使用场景。在超级管理员方案中,听起来就像客户端请求students
的集合时,它通常或者总是需要来自users
的数据,特别是subscription_type
。对象模型显然应该按照原样进行标准化,但这并不是说资源必须是,或者必须始终是。
我使用了几种不同的模式来使类似的场景更有效。哪个(如果有的话)适用取决于客户端如何使用资源。
这是将全部或部分两个或多个域对象(例如student
和user
)组合到一个资源中。
由于所有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”响应。
这两种方式都有效,并影响您在客户端应用上处理响应的方式。 (我个人而言,更喜欢后者,因为它对客户来说更具描述性。)
希望这有帮助:)