Experiment with Relay and GraphQL #4319
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Long story... but I'll try to keep it short.
So, recently I was doing some work on the REST API in order to provide better syncing for Jetpack sites, and to ultimately serve Jetpack site GET requests directly from WPCOM.
As part of this work I ended up refactoring some of the primary objects (Site and Post so far) into what I call the "Site Abstraction Layer", or SAL, which basically provides an object model to retrieve API fields and neatly separate rendering of those fields between WPCOM, Jetpack, and Jetpack-Shadow-Site implementations.
The goal of this was to allow myself to separate out platform-specific hacks and ship less WPCOM code with Jetpack, but along the way I realised that I'd just created an object graph for WordPress.com.
And then I thought "I wonder how easy it would be to port this to a GraphQL API".
As it turns out, reasonably easy.
What is GraphQL?
GraphQL is query language that mirrors React's composition-oriented approach. The idea is that by composing just the data you need in one request rather than many, you can overcome bandwidth and latency limitations of building very rich apps against a REST API, where separate requests must be issued for each object or list, and all fields are returned every time (by default, anyway).
In theory this means less work for the client, AND the network, AND the server. In practice, of course, it's complicated.
The prototype GraphQL server that I implemented uses the graphql-php library.
The server side of this is in patch D1443-code. Apply the patch to your WPCOM sandbox in order to try this out.
What is Relay?
Relay is a React library for binding GraphQL queries and fragments to components. When a component tree under a
Relay.RootContainer
is rendered, it fetches all the data at once, compiling together the data requirements of the entire component tree.The benefits of Relay IMO is (1) that it's an officially endorsed data binding solution for React, and (2) that it allows components to be developed in a moderately decoupled manner both from each other and from the server. In addition, by using babel-relay-plugin it validates the syntax of all queries against the server's schema at compile time - extremely handy, both for validating the client AND the server implementation.
The isolation of Relay queries also makes testing easier - you only need to satisfy the declared data dependencies of the component wrapper in order to build a valid test.
How do I run this?
make run
and head to http://calypso.localhost:3000/devdocs/data-bindingHow do I update the schema.json?
The client needs access to a schema.json model that matches the server. To do that we have to issue a special query to the graphql endpoint and dump the results in a file.
Eventually this could be an automated part of the build process.
(note: this is not valid graphql, it's a hack that I put in for specifically requesting the schema)
server/relay/schema.json
How do I test out graphql queries?
Very similar to the above, POST to https://public-api.wordpress.com/rest/v1.1/graphql with something like this as your
query
parameter:How does this work?
By default Relay issues requests to
$(host)/graphql
. I implemented a custom network layer which instead uses the wpcom object to retrieve responses frompublic-api.wordpress.com
using whatever underlying protocol wpcom is configured to use.Everything from there on is standard Relay - implement a container with a root query (typically Relay you'll see this called "viewer". I called it "site").
Right now it's hard-coded to retrieve my own site, goldsounds.com. You can see the hard-coded parameter in the AppRoute instantiation:
In the real world we'd probably have the user as the root and then fetch sites etc. under that.
This code also demonstrates basic composition, where we have an
App
component which displays the site URL, and a nestedSitePlan
component that renders the plan name.Unsolved problems
Oh, so many.