假设我们的学校拥有一些数据,包括姓名和学生列表,学生也拥有一些数据,包括他们注册的类(class)和学校的引用信息。在客户端:
- 我想显示一个屏幕,其中显示有关学校的信息,其中包括按姓名列出的所有学生的列表。
- 我想显示一个屏幕,其中显示有关学生的信息,包括他们的学校名称和他们正在学习的类(class)名称。
- 我想缓存此信息,以便我可以显示相同的屏幕,而无需等待新的获取。我应该能够从一个学校到另一个学生,然后再返回学校,而无需再次去学校。
- 我想仅通过一次获取来显示每个屏幕。从学校页面转到学生页面可以单独获取,但我应该能够在一次获取中显示学校的完整学生姓名列表。
- 我希望避免重复数据,这样,如果学校名称发生更改,一次更新学校的提取操作将导致学校页面和学生页面上显示正确的名称。
是否有一个好方法来完成所有这一切,或者是否必须取消一些限制?
第一种方法是拥有一个执行以下操作的 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 相互引用,然后将对象存储在不同的数据存储中。但是,嵌套在 school
内的 student
对象并不是一个完整的对象——它不包含嵌套的类(class),也不包含对学校的引用。同样,student
内部的 school
对象没有所有在校学生的列表。在数据存储中存储对象的部分表示会导致客户端出现一堆复杂的逻辑。
我们可以存储学校和学生及其嵌套的部分对象,而不是标准化这些对象。然而,这意味着数据重复——杰斐逊高中的每个学生都会嵌套学校的名称。如果学校名称在获取特定学生之前发生更改,那么我们会显示该学生的正确学校名称,但在其他地方显示错误的名称,包括在“学校详细信息”页面上。
另一种方法可能是将 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]
}
我们总是拥有对象及其所有引用的“完整”表示,因此在数据存储客户端中存储这些信息非常容易。但是,这需要多次提取才能显示每个屏幕。要显示有关学生的信息,我们必须获取该学生,然后获取他们的学校以及他们的类(class)。
是否有一种更智能的方法可以让我们仅缓存每个对象的一个副本,并防止多次获取以显示基本屏幕?
最佳答案
您可能会混合两个概念:存储和表示。您可以返回非标准化表示(您建议的第一个选项)而,而无需将这些“部分”对象存储在数据库中。
因此,我建议尝试返回非标准化表示,但将它们标准化存储(如果您使用的是关系数据库)。
此外,还有一个改进建议:您可能希望在表示中使用正确的 URI 而不是 Id。您可能希望客户端知道从“哪里”获取该对象,因此只提供 URI 会更容易。否则,客户端需要弄清楚如何从 Id 中生成 URI,而这通常最终会在客户端中进行硬编码,这在 REST 中是禁忌。
关于rest - API设计: Caching “partial” nested objects,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38821057/