Relay FAQ: Facebook's Data-fetching Framework for React
gist.github.com
gist.github.com
We haven't yet finalized what API we will provide when we open source Relay. You'll certainly get one object, called Relay, however ;)
Here's a photo from the presentation that shows an example: https://twitter.com/devonbl/status/560532680513556481.
Example: To render a UI view, I need to fetch a list of friends, a list of posts, and a list of notifications. All 3 of these data types (friends, posts, notifications) have users associated with them. Instead of fetching users for the 3 data types 3 separate times, I need to flatten that into a single call. I end up with something like this:
var [posts, friends, notifs] = yield [
getPosts(),
getFriends(),
getNotifs()
]; // executes in parallel
var userIDs = new Set();
userIDs.addAll(posts.map(p => p.userID));
userIDs.addAll(friends.map(f => f.userID));
userIDs.addAll(notifs.map(n => n.userID));
var users = yield getUsers(userIDs.toArray());
return {posts, friends, notifs, users};
You can see where this gets cumbersome. I have to compose one of these for every kind UI view at the root level. On the one hand it's very explicit and the flow of data is very clear, but it also means relationships between data are dupicated in more than one place (often many places).Could GraphQL help with that scenario?
If I understand your post correctly, I think it could. GraphQL prefers to expose full objects, rather than IDs, which lets you query for data inside objects at the same time. So for your example above, you would only need one GraphQL query:
viewer() {
posts {
node {
author { id, name, favorite_color },
// any other post data you want
}
},
friends {
node {
id,
name,
favorite_color,
}
},
notifications {
node {
source { id, name, favorite_color },
// any other notification fields you want
}
},
}
The "id, name, favorite_color" is just a sample set of fields, you could replace it with whichever your components needed. Relay also has functionality to avoid duplicating the set of fields, which is especially useful when you want to add or remove a field from what a reusable component needs.If you like that kind of control flow, check out the library we wrote to do it: https://github.com/storehouse/engen
My concern is regarding the server-side implementation of the GraphQL endpoint. My understanding is that GraphQL endpoints couple tightly to a graph-oriented backend. Facebook already has TAO so it's a no-brainer, but how feasible do you think a normal SQL-based backend can adapt to efficiently process arbitrary GraphQL queries? Or would it be easier to switch to a graph-oriented database (e.g. neo4j) instead? The former option seems to be quite an engineering endeavor, while the latter is just too risky right now.
Having experimented with neo4j a year ago, I would concur that it hasn't been battle-tested for use as a high-availability database for web apps; it was used much more for offline analytics AFAIK. Thingdom did some REALLY cool things using neo4j from JS, and their ideas for modeling news feeds were really mindblowing, but I'm hesitant to put anything mission-critical on it just yet from both a technical-debt perspective and a speed/scalability perspective.
In our framework, it's mostly event based, so if some data changes, events are fired and then things happen based on subscriptions. Just wondering what advantages are offered here over that setup.
> This means that only the fields of an object that a component explicitly asks for will be accessible to that component, even if other fields are known and cached in the store (because another component requested them). We call this masking, and it makes it impossible for implicit data dependency bugs to exist latently in the system.
BreezeJS is a stand-alone data library for SPAs which takes care of managing the lifecycle of data objects; querying, fetching, caching is all taken care of. Queries use OData by default, but implements a specific subset of the query language that can rendered down and used against REST apis. Breeze also provides server libraries for different stacks to easily integrate and get up and running.
Granted the usecase of embedding declarative queries as part of a component which gets composed along with other components+queries is unique to React, but I speculate it wouldn't be too difficult to implement within Breeze.
All that said, it will be nice to see another rich-data management library to compare and contrast. The days of painstakingly writing business objects in 34 places will end.
GraphQL sounds tremendously exciting.
Especially excited at the idea of a single store. I've always had a little bit of a beef with Flux when it came to interdependencies within stores.
I feel like one of the problems with react that is currently not well solved is the integration of a client and server side router for a truly isomorphic application. There have been quite a few implementations that rely on a single om-like state that they serialize and deserialize to the client. Relay feels like it would fit extremely well into this paradigm.
None of this tech requires much promotion since it's clearly the new hotness, but there is a silent majority of developers that would appreciate knowing when they can start paying attention professionally. Hopefully soon all JavaScript projects will include a list of supported platforms alongside their corner GitHub banner.
(source: I'm an engineer on Relay)
First, for the framework-level handling of fetching all data before rendering, where the data needed by each component is defined in each component, just copy how it's done in react-router's async-data example [1], modified to expect a hash of promises as in [2].
The promises return Backbone-Relational models [3]. You can model arbitrary relations using Backbone-Relational, although many-to-many is apparently kind of hacky (but just needs work to be seamless). It supports parsing REST API responses with nested models and collections as related models. A REST API generator like Flask-Restless [4] creates these responses with a single efficient query.
You have the flexibility to either sync all models before rendering, or render any component without all data already being fetched, and have it automatically re-render when loaded.
Components subscribe and unsubscribe to model events at the proper points in the component lifecycle using react-backbone-component.[5] I missed this and wrote my own version [6] before I found it, but mine is cleaner, slightly more featureful, and presents a simpler API.
Anyway, this requires some work to pull together, but I think it presents a viable alternative that:
- uses existing libraries that do one thing well and allows as much departure from each elements of the architecture as you want
- works with react-router, which is the shit
- works with your existing REST API
Relay looks wonderful, but it's possible to build the abstractions that do pretty much the same thing that support existing REST APIs.
[1] https://github.com/rackt/react-router/blob/master/examples/a...
[2] https://github.com/rackt/react-router/wiki/Announcements
[3] http://backbonerelational.org/
[4] https://flask-restless.readthedocs.org/en/latest/