One thing I keep running into is that for a few of my app ideas, I'm not really interested in just having static queries known at build time, like Relay and Apollo are designed for. I specifically want them to be dynamic and actually based on what components get rendered.
That's great if the ProfilePage component knows that it only contains the Header, Sidebar, and TweetList components. Since they're designed for static queries, both Relay and Apollo suffer from this shortcoming: the parent query needs to know about every component that could possibly add fragments ahead of time, and pull them all in. In my opinion, this really fails at fulfilling the promise of components – the parent shouldn't need to know what all its descendants do.
What if the rendered components are more dynamic? Putting @skip directives on every field is not really an option (and then you need a matching query $variable for every directive.)
If you think of the query as more of a template, then you could have portions of the query that are like "template blocks" that other components could extend, e.g.:
...then descendant components could have access to `userFragments` as an extension point. I'm not yet sure if it's a terrible idea, but I started a project just the other day to experiment with it: https://github.com/exogen/apollo-dynamic-queries
It sounds like your child components should be fetching their own data via their own graphql queries rather than consuming it as props from the parent that's rendering them.
That way the parent can just render whatever components it wants without having to worry about what data they require.
This is a classic static/dynamic problem. Luckily, in the case of React, there may be a really good solution that covers most necessary use cases. First, an analogy:
Consider Ruby's method_missing and corresponding respond_to? methods [1]. method_missing may respond to a method dynamically, but respond_to? should return true if a method will be responded to. If you constrain yourself to normal methods, or carefully defined method_missing bodies, you can predict with 100% accuracy, but what if you do something like this?
class Whoops
def method_missing(method)
if method == :fancy and Random.rand > 0.5
"it's your lucky day!"
else
super(method)
end
end
def respond_to?(method, include_private = false)
if method == :fancy
true # Well, actually, "maybe?".
else
super
end
end
end
Temporarily ignoring the problem created by randomness: Implementing respond_to? methods is annoyingly redundant. In order to fully-automate the process of implementing respond_to?, you'd need to analyze a method_missing implementation. In the common case, this is static type inference. In the limit case, this is arbitrary abstract interpretation.
However, effectful code, such as this random example, is provably impossible to analyze correctly! You need to have some conservative approximation. Returning true from respond_to? for the :fancy method means that respond_to? should actually be called might_respond_to?.
OK, now back to React and GraphQL: Luckily, over-fetching data is usually not that big a deal (as long as you're within bandwidth constraints). It's often desirable to! Since you might need that data soon when the view changes. Knowning this, it's safe to assume a method for assembling a GraphQL query from fragments can be conservative. That's essentially what a totally static, manual composition of query fragments does. If that's a tight enough approximation for you (like some other commenters have implied) then great! But what if it's not?
Luckily, virtual DOMs are dramatically simpler and less powerful than arbitrary method_missing implementations. If your render method is already pure, you can call it an extra time to use it as its own abstract interpretation. It will produce a virtual DOM, which you can then analyze yourself. For example:
Here, the gatherQuery method will walk the objects returned by our monkey-patched createElement method, composing query fragments along the way. By following the component references, you can find static methods (easy!), or even instantiate components to do recursive renders yourself (this gets hairy, since React doesn't really make any of this public API). You can do something pretty simple with this: Just hard code a few component types to make some limited dynamic decisions, fallback to static over-query beyond that. Or you can get really fancy and do recursive rendering and analysis, if you really want to.
I really love this approach, I have been thinking about it for some time now... However, as much as I like it, it seems that implementing a GraphQL server is not an easy task, and getting an in-depth understanding of how GraphQL works seems quite challenging.
I can devote a few days to read the JSON-API spec (http://jsonapi.org/) and get a pretty good understanding of it. I wish there were a way to consume JSON-API based APIs in the same declarative way GraphQL provides.
I'm thinking that a library that "translates" GraphQL queries to JSON-API requests will be a great solution.
GraphQL is something that's relatively simple (and brilliant) but is one of those things that you just need to try properly first for it to click, especially if you have a background of implementing tons of REST based services.
The GraphQL related tools are top notch and implementing GraphQL server isn't any harder than a REST based server would be (one could even argue that it would be simpler).
Even if you don't want to implement everything from scratch, tools like Postgraph[0] exists that pretty much automate it for you.
I made a simple tutorial[1] on wrapping an existing API with GraphQL here which goes through basics of settings up too.
> it seems that implementing a GraphQL server is not an easy task
It's actually really easy, I encourage you to look into it! I've written plenty of APIs over the years and it's one of the more pleasant experiences I've had.
Sure, but you're asking your server to support a full query language. Even with data-fetch on a js-impl (or ... a hell of a lot of by-hand tooling in Python with Graphene), this overhead really hurts your qps.
To be honest, I sort of wonder if the right place to implement the GQL interpretation and scheduling layer is in a service-worker.
That way, the client devs who love this complex query language can also support the queries they need and ensure their calling conventions don't violate performance boundaries in the gql server implementation.
Facebook’s Relay solves the throughput problem by effectively precompiling queries. Their production apps only make a subset of the requests of the full graphql language - and those are frozen at deploy/compile time. In some sense this makes their production graphql more like “auto-generated REST” from the server’s perspective.
That said, thinking of this in terms of client vs server devs isn’t useful - it’s not like anyone on the team want to see the servers burn. The beauty of graphql is it’s descriptiveness - you could create a query performance score and fail CI if your main page queries are hitting too high of a cost. A meet up in SF last year had some FB engineers discussing this - they do something along these lines before shipping their android/iOS apps.
It's really not that hard to build a relatively optimal GraphQL server. Obviously it requires paying careful attention to performance, and to take steps to mitigate abuse (query whitelists, complexity caps etc). If you were to move the implementation off the server and into the client you'd use a lot of the benefits of GraphQL in the first place (performance being a major one).
Question for someone with experience with graphql. I have a data heavy react application I'm working on that would benefit from something like this, but almost every single component has the ability to refetch it's data individually. If you have all of these fragments being passed up to the single query being called, how do you handle a situation where you want the explicitness of refetching only one of those fragments, but getting it on in one initial call?
It's less about component-level refetching (though you can), it's more about the strong data specificity and composition that is the point of this article. That said, it's up to your query builder to figure out intelligent refreshing / refetching. I use Relay, and it's pretty good at this.
Apollo supports batching queries at the transport layer. graphql-ruby and I'm sure other graphql servers support this out of the box, which means with about ~10 LOC changed you can have your cake (separate queries for independent update) and eat it (combined into one initial call).
I don’t understand... doesn’t GraphQL encourage embedding full queries into the client app? It’s not SQL but it’s equivalent. Isn’t this a road of pain for any project that is long-lived or scaled.
I guess I can see it sitting between a data cache — that is filled by a set of relatively large-granularity fixed queries that can have a decent cache validation mechanism — and the client UI. Maybe that’s how it’s actually implemented? But then it seems like that would often be better (at least much of the time) for that data cache to be client-side.
You do want a way to pass user filter conditions back through the data access pipeline (but not business logic where-clause conditions) all the way back to the data store, but those should still be constrained.
The schema should still be documented somewhere, like any API. But even if it's not: GraphQL supports a special "introspection query" that will tell you the entire schema that you can query. Pointing a tool like GraphiQL (https://github.com/graphql/graphiql) at a GraphQL endpoint will even run the introspection query automatically and turn the result into rendered explorable documentation. That's how you figure out what to query.
Usually GraphQL APIs are served alongside a GraphiQL client, which lets you run queries, and read the schema and docs for that API. See, for example, the Star Wars API example: http://graphql.org/swapi-graphql/
I dont use fragments, I feel if I need a fragment, the jsx file is too bloated just make more components and higher order components that connect with a small slice of your graphl queries. This is probably causes more duplication but I'll copy and paste if it makes things easier to read
I was curious if anyone was going to mention this. We had been looking at GraphQL for our latest project, but realized datomic + pull patterns + re-frame was a more integrated fit.
I hate jacking threads pointing out X instead of Y, but in this case it feels warranted.
[+] [-] exogen|8 years ago|reply
Consider this query from the article:
That's great if the ProfilePage component knows that it only contains the Header, Sidebar, and TweetList components. Since they're designed for static queries, both Relay and Apollo suffer from this shortcoming: the parent query needs to know about every component that could possibly add fragments ahead of time, and pull them all in. In my opinion, this really fails at fulfilling the promise of components – the parent shouldn't need to know what all its descendants do.What if the rendered components are more dynamic? Putting @skip directives on every field is not really an option (and then you need a matching query $variable for every directive.)
If you think of the query as more of a template, then you could have portions of the query that are like "template blocks" that other components could extend, e.g.:
...then descendant components could have access to `userFragments` as an extension point. I'm not yet sure if it's a terrible idea, but I started a project just the other day to experiment with it: https://github.com/exogen/apollo-dynamic-queries[+] [-] atticusberg|8 years ago|reply
That way the parent can just render whatever components it wants without having to worry about what data they require.
[+] [-] brandonbloom|8 years ago|reply
Consider Ruby's method_missing and corresponding respond_to? methods [1]. method_missing may respond to a method dynamically, but respond_to? should return true if a method will be responded to. If you constrain yourself to normal methods, or carefully defined method_missing bodies, you can predict with 100% accuracy, but what if you do something like this?
Temporarily ignoring the problem created by randomness: Implementing respond_to? methods is annoyingly redundant. In order to fully-automate the process of implementing respond_to?, you'd need to analyze a method_missing implementation. In the common case, this is static type inference. In the limit case, this is arbitrary abstract interpretation.However, effectful code, such as this random example, is provably impossible to analyze correctly! You need to have some conservative approximation. Returning true from respond_to? for the :fancy method means that respond_to? should actually be called might_respond_to?.
OK, now back to React and GraphQL: Luckily, over-fetching data is usually not that big a deal (as long as you're within bandwidth constraints). It's often desirable to! Since you might need that data soon when the view changes. Knowning this, it's safe to assume a method for assembling a GraphQL query from fragments can be conservative. That's essentially what a totally static, manual composition of query fragments does. If that's a tight enough approximation for you (like some other commenters have implied) then great! But what if it's not?
Luckily, virtual DOMs are dramatically simpler and less powerful than arbitrary method_missing implementations. If your render method is already pure, you can call it an extra time to use it as its own abstract interpretation. It will produce a virtual DOM, which you can then analyze yourself. For example:
Here, the gatherQuery method will walk the objects returned by our monkey-patched createElement method, composing query fragments along the way. By following the component references, you can find static methods (easy!), or even instantiate components to do recursive renders yourself (this gets hairy, since React doesn't really make any of this public API). You can do something pretty simple with this: Just hard code a few component types to make some limited dynamic decisions, fallback to static over-query beyond that. Or you can get really fancy and do recursive rendering and analysis, if you really want to.[1] http://blog.enriquez.me/2010/2/21/dont-forget-about-respond-...
[+] [-] otto_ortega|8 years ago|reply
I can devote a few days to read the JSON-API spec (http://jsonapi.org/) and get a pretty good understanding of it. I wish there were a way to consume JSON-API based APIs in the same declarative way GraphQL provides.
I'm thinking that a library that "translates" GraphQL queries to JSON-API requests will be a great solution.
[+] [-] petetnt|8 years ago|reply
The GraphQL related tools are top notch and implementing GraphQL server isn't any harder than a REST based server would be (one could even argue that it would be simpler). Even if you don't want to implement everything from scratch, tools like Postgraph[0] exists that pretty much automate it for you.
I made a simple tutorial[1] on wrapping an existing API with GraphQL here which goes through basics of settings up too.
[0] https://github.com/postgraphql/postgraphql [1] https://github.com/motleyagency/devday-tutorials/blob/master...
[+] [-] exogen|8 years ago|reply
It's actually really easy, I encourage you to look into it! I've written plenty of APIs over the years and it's one of the more pleasant experiences I've had.
I wrote this simple 35-line GraphQL server implementing a demo schema in 2 minutes just while I was replying to your comment: https://gist.github.com/exogen/d5ddf86dd7f9efd15d3fabdace759...
[+] [-] aarpmcgee|8 years ago|reply
[+] [-] sorenbs|8 years ago|reply
[+] [-] KirinDave|8 years ago|reply
To be honest, I sort of wonder if the right place to implement the GQL interpretation and scheduling layer is in a service-worker.
That way, the client devs who love this complex query language can also support the queries they need and ensure their calling conventions don't violate performance boundaries in the gql server implementation.
[+] [-] NightMKoder|8 years ago|reply
That said, thinking of this in terms of client vs server devs isn’t useful - it’s not like anyone on the team want to see the servers burn. The beauty of graphql is it’s descriptiveness - you could create a query performance score and fail CI if your main page queries are hitting too high of a cost. A meet up in SF last year had some FB engineers discussing this - they do something along these lines before shipping their android/iOS apps.
[+] [-] andrewingram|8 years ago|reply
[+] [-] kotojo|8 years ago|reply
[+] [-] brokentone|8 years ago|reply
[+] [-] mattbessey|8 years ago|reply
[+] [-] jmull|8 years ago|reply
I guess I can see it sitting between a data cache — that is filled by a set of relatively large-granularity fixed queries that can have a decent cache validation mechanism — and the client UI. Maybe that’s how it’s actually implemented? But then it seems like that would often be better (at least much of the time) for that data cache to be client-side.
You do want a way to pass user filter conditions back through the data access pipeline (but not business logic where-clause conditions) all the way back to the data store, but those should still be constrained.
[+] [-] mattmurdog|8 years ago|reply
I don't know what I need. Server tells me I need {allthedogs}. Now I know to query for {allthedogs}... what's the point of GraphQL?
[+] [-] exogen|8 years ago|reply
[+] [-] epidemian|8 years ago|reply
[+] [-] ojr|8 years ago|reply
[+] [-] akmiller|8 years ago|reply
[+] [-] erichmond|8 years ago|reply
I hate jacking threads pointing out X instead of Y, but in this case it feels warranted.
[+] [-] avodonosov|8 years ago|reply
[+] [-] fenollp|8 years ago|reply
The only job of the future will be AI-assisted design.
[+] [-] gipp|8 years ago|reply