Tuesday, August 25, 2015

Functional principles come together in GraphQL at React Rally

Sometimes multiple pieces of the industry converge on an idea from
different directions. This is a sign the idea is important.

Yesterday I spoke at React Rally (video coming later) about the
confluence of React and Flux in the front end with functional
programming in the back end. Both embody principles of composition, declarative
style, isolation, and unidirectional flow of data.

In particular, multiple separate solutions focused on:

  •   components declare what data they need
  •   these small queries compose into one large query, one GET request
  •   the backend gathers everything and responds with data in the requested format

This process is followed by Falcor from Netflix (talk by Brian Hunt) and GraphQL from Facebook (talks by Lee Byron and Nick Schrock, videos later). Falcor adds caching on the client, with cache
invalidation defined by the server (smart; since the server owns
the data, it should own the caching policy). GraphQL adds an IDE for
queries, called GraphiQL (sounds like "graphical"), released as
open source for the occasion! The GraphQL server provides introspection
into the types supported by its query language. GraphiQL uses this to let the developer
work with live, dynamically fetched queries. This lets us explore the available
data. It kicks butt.

Here's an example of GraphQL in action. One React component in a GitHub client might specify that it needs
certain information about each event (syntax is approximate):
{
  event {
    type,
    datetime,
    actor {
      name
    }
  }
}
and another component might ask for different information:
{  event {    actor {      image_uri    }  }}

The parent component assembles these and adds context, including
selection criteria:
{  repository(owner:"org", name:"gameotron") {    event(first: 30) {       type,       datetime,       actor {         name,         image_url      }    }  }}
Behind the scenes, the server might make one call to retrieve the repository,
another to retrieve the events, and another to retrieve each actor's
data. Both GraphQL and Falcor see the query server as an abstraction
layer over existing code. GraphQL can stand in front of a REST
interface, for instance. Each piece of data can be
fetched with a separate call to a separate microservice, executed in
parallel and assembled into the structure the client wants. One GraphQL
server can support many version of many applications, since the
structure of returned data is controlled by the client.
The GraphQL server assembles all the
results into a response that parallels the structure of the client's
query:
{  "repository" : {    "events" : [{      "type" : "PushEvent",      "datetime" : "2015-08-25Z23:24:15",      "actor" : {        "name" : "jessitron",        "image_url" : "https://some_cute_pic"      }    }    ...]  }}
It's like this:
The query is built as a composition of the queries from all the components. It goes to the server. The query server spreads out into as many other calls as needed to retrieve exactly the data requested.
The query is composed like a fan-in of all the components'
desires. On the server this fans out to as many back-end calls as
needed. The response is isomorphic to the query. The client then spreads
the response back out to the components. This architecture supports
composition in the client and modularity on the server.
The server takes responses from whatever other services it had to call, assembles that into the data structure specified in the query, and returns that to the client. The client disseminates the data through the component tree.
This happens to minimize network traffic between the client and server.
That's nice, but what excites me are these lovely declarative queries that
composes, the data flowing from the parent component into all the
children, and the isolation of data requests to one place. The exchange
of data is clear. I also love the query server as an abstraction over
existing services; store the data bits in the way that's most convenient
for each part. Assembly sold separately.

Seeing similar architecture in Falcor and GraphQL, as well as in
ClojureScript and Om[1] earlier in the year, demonstrates that this is
important in a general case. And it's totally compatible with
microservices! After React Rally, I'm excited about where front ends are
headed.


[1] David Nolen spoke about this process in ClojureScript at Craft Conf
earlier this year. [LINK]

No comments:

Post a Comment