Let's say we have schools with some data including a name and a list of students, and students with some data including courses they're enrolled in and a reference to their school. On the client:
- I'd like to show a screen that shows information about a school, which includes a list of all of its students by name.
- I'd like to show a screen that shows information about a student, including the name of their school and the names of courses they're taking.
- I'd like to cache this information so that I can show the same screen without waiting on a new fetch. I should be able to go from school to student and back to school without fetching the school again.
- I'd like to show each screen with only one fetch. Going from the school page to the student page can take a separate fetch, but I should be able to show a school with the full list of student names in one fetch.
- I'd like to avoid duplicating data, so that if the school name changes, one fetch to update the school will lead to the correct name being shown both on the school page and the student pages.
Is there a good way to do all of this, or will some of the constraints have to be lifted?
A first approach would be to have an API that does something like this:
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"
}
...
]
}
An advantage of this approach is that, for each screen, we can just do a single fetch. On the client side, we could normalize schools and students so that they reference eachother with IDs, and then store the objects in different data stores. However, the student
object nested inside of school
isn't a full object -- it doesn't include the nested courses, or a reference back to the school. Likewise, the school
object inside of student
doesn't have a list of all attending students. Storing partial representations of objects in data stores would lead to a bunch of complicated logic on the client side.
Instead of normalizing these objects, we could store schools and students with their nested partial objects. However, this means data duplication -- each student at Jefferson High would have the name of the school nested. If the school name changed just before doing a fetch for a specific student, then we'd show the right school name for that student but the wrong name everywhere else, including on the "school details" page.
Another approach could be to design the API to just return the ids of nested objects:
GET /school/1
{
id: 1,
name: "Jefferson High",
students: [1, 2]
}
GET /student/1
{
id: 1,
name: "Joel Kim",
school: 1,
courses: [3, 5]
}
We'd always have "complete" representations of objects with all of their references, so it's pretty easy to store this information in data-stores client side. However, this would require multiple fetches to show each screen. To show information about a student, we'd have to fetch the student and then fetch their school, as well as their courses.
Is there a smarter approach that would allow us to cache just one copy of each object, and to prevent multiple fetches to show basic screens?