THE PROMPT
If you were to build Google Calendar using relay, how would you structure the GraphQL schema and the Relay containers/components to properly handle showing & hiding multiple calendars?
THE ATTEMPT
One might imagine a schema like this:
viewer {
user {
calendars(calendarIds: [String]) {
edges,
node {
name,
id,
events(dates: [Date]) {
... edges, node, eventinfo...
}
}
}
}
}
}
So, I can pull down all the calendars and all the events, or a specific calendar, or what have you.
Structuring the Relay Containers and components, I would imagine the following:
<CalendarView Container>
<CalendarView>
<WeekView> or <MonthView> or <Agenda> etc...
<Event>
Such that the CalendarView relay container sets up the fragment requesting the calendars, and the CalenderView
component uses setVariables
to toggle the showing/hiding of that calendar in the view.
The problem that I'm encountering (and that's making my head spin) is that the Day
/Week
/Month
/Agenda
components are combinatorial views — that is, they require the data from all selected events.
THE PLOT THICKENS
Now, that sounds just fine — have the CalendarView
set the calendarId variables and pass the resulting events down, right? Well... kind of. Now the fragment for CalendarView
is constructed with a set of calendarIds
, such that toggling one calendar
on or off changes the entire tree of what is to be fetched.
THE GOTCHA?
As far as I can tell, relay sees each combination of calendarIds
as an entirely different fetch. So, when I toggle on a new id
it fetches all the events, even for those calendars I've already fetched.
Put code-wise:
fragment calendar(calendarIds: [1, 2]) { ... }
Is an entirely different fetch from:
fragment calendar(calendarIds: [1, 2, 3]) { ... }
This is ... bad. There can be a lot of events on those calendars and the over-fetching is a killer.
In theory, I could create a container per calendar, but then how would I combine the events on those calendars and pipe them into a common sub-component? The calendars can't be layered because events need to move around in reaction to other events, even those on separate calendars (shifting left/right to show them side-by-side).
Thoughts? My brain hurts.
GraphQL is designed to make APIs fast, flexible, and developer-friendly. It can even be deployed within an integrated development environment (IDE) known as GraphiQL. As an alternative to REST, GraphQL lets developers construct requests that pull data from multiple data sources in a single API call.
The core difference between GraphQL and REST APIs is that GraphQL is a specification, a query language, while REST is an architectural concept for network-based software. Note: This article is mostly server-side related. GraphQL is gaining momentum as a successor to REST APIs.
No, but this is a common misconception. GraphQL is a specification typically used for remote client-server communications. Unlike SQL, GraphQL is agnostic to the data source(s) used to retrieve data and persist changes. Accessing and manipulating data is performed with arbitrary functions called resolvers.
GraphQL is a flexible query language that uses a type system to efficiently return data with dynamic queries. SQL(structured query language) is an older, more adopted language standard used specifically for tabular/relational database systems. Consider GraphQL if you want your API to be built on a NoSQL database.
Put code-wise,
calendar(calendarIds: [1, 2])
is an entirely different query fromcalendar(calendarIds: [1, 2, 3])
Yup. GraphQL doesn't assign semantics to field arguments, so Relay (nor any other GraphQL client) doesn't know that the calendarIds
arguments correspond to the ids of the results. This is a common enough use-case, though, that Relay supports a special nodes(ids: [ID!])
root field (on the Query type) that is treated as you were expecting. To use it, implement a nodes
field in your schema that returns results as an array whose order matches that of the input ids, with null entries for any results that couldn't be loaded. E.g. if the input ids are [1,2,3]
, you'd return [result1, result2, result3]
. When using this field, Relay will diff arguments arguments against previously fetched data (because it makes the assumption that the arguments of this particular field have a semantic meaning as ids).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With