我们假设我们的学校有一些数据,包括姓名和学生名单,以及有一些数据的学生,包括他们注册的课程和他们学校的参考。在客户端:
是否有一个很好的方法来完成所有这些,或者是否必须解除一些限制?
第一种方法是使用这样的API:
GET /school/1
{
id: 1,
name: "Jefferson High",
students: [
{
id: 1
name: "Joel Kim"
},
{
id: 2,
name: "Chris Green"
}
...
]
}
GET /student/1
{
id: 1,
name: "Joel Kim",
school: {
id: 1,
name: "Jefferson High"
}
courses: [
{
id: 3
name: "Algebra 1"
},
{
id: 5,
name: "World History"
}
...
]
}
这种方法的一个优点是,对于每个屏幕,我们只需要进行一次获取。在客户端,我们可以规范学校和学生,以便他们互相引用ID,然后将对象存储在不同的数据存储中。但是,嵌套在student
内的school
对象并不是一个完整的对象 - 它不包含嵌套的课程,也不包含回学校的参考。同样,school
内的student
对象也没有所有参加学生的列表。在数据存储中存储对象的部分表示将导致客户端上的一堆复杂逻辑。
我们可以为学校和学生存储嵌套的部分对象,而不是规范化这些对象。然而,这意味着数据重复 - Jefferson High的每个学生都会将学校的名称嵌套。如果在为特定学生取得学校名称之前更改了学校名称,那么我们会为该学生显示正确的学校名称,但在其他地方显示错误的名称,包括学校详细信息"页。
另一种方法可能是设计API以仅返回嵌套对象的ID:
GET /school/1
{
id: 1,
name: "Jefferson High",
students: [1, 2]
}
GET /student/1
{
id: 1,
name: "Joel Kim",
school: 1,
courses: [3, 5]
}
我们总是"完成"具有所有引用的对象的表示,因此将此信息存储在数据存储客户端中非常容易。但是,这需要多次提取才能显示每个屏幕。为了显示学生的信息,我们必须取得学生,然后取回他们的学校,以及他们的课程。
是否有一种更智能的方法可以让我们只缓存每个对象的一个副本,并防止多个提取显示基本屏幕?
答案 0 :(得分:3)
您可能会混合两个概念:存储和表示。你可以回馈一个非标准化的表示(你建议的第一个选项)没有也存储那些" partial"数据库中的对象。
所以我建议尝试返回非规范化的表示,但存储它们是规范化的(如果你使用的是关系数据库)。
此外,还有一个改进建议:您可能希望在表示中使用正确的URI而不是ID。您可能希望客户知道"其中"为了获得该对象,因此更容易提供URI。否则,客户端需要弄清楚如何从Id中生成URI,并且通常最终在客户端中进行硬编码,这在REST中是禁止的。