Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GraphQL & Relay Filtering UI

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.

like image 859
Matt Martin Avatar asked Dec 09 '16 00:12

Matt Martin


People also ask

What is GraphQL used for?

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.

What is GraphQL vs REST API?

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.

Is GraphQL same as SQL?

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.

Is GraphQL SQL or NoSQL?

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.


1 Answers

Put code-wise, calendar(calendarIds: [1, 2]) is an entirely different query from calendar(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).

like image 185
Joe Savona Avatar answered Oct 17 '22 22:10

Joe Savona