API - 多个请求与分离用户角色
-
22-12-2019 - |
题
我正在开发单页应用程序的前端,我必须列出一些学生。每个学生都依附于某个特定的 user_id
这是当我执行时 API 为所有用户角色(超级管理员、管理员、教授、学生)返回的内容 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
),仅适用于 GET /users/:id
所以当我在一个页面上列出 20-30 名学生时 GET /students/
, ,为了得到 subscription_type
, ,我还需要执行 20-30 个额外请求,每个学生一个。
我和 API 人员讨论了这个问题,我被告知将额外的数据包含到 students
“这不是 RESTful 的做法”,“它会进一步减慢响应时间”以及“30 个额外请求的重量还不算一大块”。
我对 API 工作一无所知,所以我真的没有发言权,但我是否疯狂地认为页面加载 30 个请求是可笑的?
那么接下来怎么办?我要继续执行额外的请求吗?他是否应该将每个用户角色的响应分开并仅包含每个角色所需的内容?是什么 正确的方法 处理这个?
解决方案
虽然严格来说 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"
...
}
}
其他提示
您在这里有两个问题,不应该将它们捆绑在一起 - 一个是为索引调用(/学生)返回的每个用户的数据,另一个是授权过程,该过程应确定可以将某些用户暴露于哪些数据。
关于数据问题 - 我认为没有具体的规则可遵循。这完全取决于您的应用程序的要求。如果 subscription_type 字段通常是不必要的,您可以考虑传递一个查询参数(例如“include_extra_data=1”)来指示您在特定请求上需要它,默认情况下不会返回它。
关于授权问题 - 这应该与您请求的数据完全无关。服务器应该能够根据用户id判断哪些数据对用户可见。(您可以查看 康康宝石][1] 作为可能的解决方案)。
因此,结合这两个问题,任何类型的用户都应该能够发出带或不带“include_extra_data”标志的“/students”请求。如果服务器发现用户未经授权查看额外数据,您可以选择 2 个选项之一 - 要么仅返回允许用户查看的数据,要么返回“401 未经授权”响应。
这两种方式都是有效的,并且会影响您处理客户端应用程序上的响应的方式。(我个人更喜欢后者,因为它对客户更具描述性)。
希望这可以帮助 :)