10 ms·
GraphQL Fragments Are the Best Match for UI Components
- KirinDave 9y agoSure, 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.
- NightMKoder 9y agoFacebook’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.
- KirinDave 9y ago> 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 I am aware of this, and it seems ridiculous to me. It discards the value of having a graph query language. I'm open to being wrong about this assessment. Why am I using a new query language if it's going to end up being exactly the same as the old rest query environment? > That said, thinking of this in terms of client vs server devs isn’t useful Considering it from a typical labor division standpoint or by technical dependency and requirements isn't useful? I disagree. > The beauty of graphql is it’s descriptiveness Which you have said the "performant" way to handle is to discard and turn into a formulaic series of bytes that is indistinguishable form a new term encoding on restful POST bodies. > you could create a query performance score and fail CI if your main page queries are hitting too high of a cost. This is exactly how everyone already tools RESTful endpoints. Whole industries are built around scoring endpoints this way. Inevitably my concern about GraphQL being hard to implement server side is inevitably met with Facebook's outer and inner solution. The outer solution: Just pretend it's graphql, really it's postbodies and we won't let you write custom queries except for column filtering (which these solutions WILL fetch). The inner solution, it has been intimated to me, is they have custom GQL libraries written in Haskell using Haxl that they don't share because the industry is too busy being afraid of it. Sadly, these don't appear to be open source (and even if they were, a lot of shops would not be equipped to use them).
- riffraff 9y ago> Why am I using a new query language if it's going to end up being exactly the same as the old rest query environment? the client controls the APIs without you touching them. It is required that the client syncs up with the server but you don't have to touch backend code to change the set of fields you want (this works for internal clients, not open APIs, clearly). If you're thinking "but I can just allow the client to select fields in my JSONAPI compliant endpoint", yes, you can, and when you add includes for nested fields, and nested selections, you basically get 90% of graphql :)
- KirinDave 9y ago> yes, you can, and when you add includes for nested fields, and nested selections, you basically get 90% of graphql :) True, but until someone provides a great software kit for doing that work, I'm not going to allow arbitrary extensions.
- andrewingram 9y agoIt'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).
- rhizome 9y agoObviously it requires paying careful attention to performance, and to take steps to mitigate abuse (query whitelists, complexity caps etc) Are these also "not that hard?"
- arianon 9y ago"Query whitelists" sounds like sending to the server something like `{"query_id": 4, "variables": ...}` instead of `{"query": ..., "variables": ...}` which are straightforward to implement using any kind of server side key-value store and a middleware that maps the `query_id` back to the corresponding `query`, a tool that can help you with this is Apollo's PersistGraphQL [1] I have no idea how I would go about implementing complexity caps though, but I guess I would do something like what GitHub has done for their own GraphQL API [2], which they explain better than I can. [1]: https://github.com/apollographql/persistgraphql https://github.com/apollographql/persistgraphql [2]: https://developer.github.com/v4/guides/resource-limitations/ https://developer.github.com/v4/guides/resource-limitations/
- exogen 9y agoAnother simple option for limiting complexity (I've considered implementing this in my GraphBrainz project): in the `context` provided to the GraphQL query resolver, increment a counter whenever a resolver requires fetching from an external API/database/etc. (whatever "too much of" would constitute abuse or just take a long time). Fail if the counter reaches some threshold. This would be really easy. Also, instead of multiplying node counts like GitHub does (which is pretty clever!), another simple option would be to look at the depth of the query (how many levels down is the deepest leaf), and fail if it's over some maximum. This is also very easy to do as you get the query AST in the `info` field of the resolver. (This one is less effective than the one above since depth doesn't totally match up with resource usage, fields can be aliased, etc. but you get the idea.)
- fenollp 9y agoAdd some ML to extract common UX patterns and generate highly personalized websites/apps. The only job of the future will be AI-assisted design.
- gipp 9y agoMachine learning is not pixie dust.
- cat199 9y agoBut what if you added some ML to extract common UX patterns to it hmm?
- weego 9y agoSounds like the perfect place to use a cryptocurrency as a distributed query ledger.
- borplk 9y agoThis has become one of my pet peeves over time. After the recent round of ML/DL/AI hype train it appears that a number of people have adopted this belief that these technologies are pixie dust you can sprinkle over any arbitrary problem and knowledge will be automatically synthesised out of nothing. Almost like an excuse to avoid having to think about a problem. "But what about ..?" "A DEEP LEARNING AI NEURAL NETWORK WOULD TOTALLY SOLVE IT RIGHT?!"
- otto_ortega 9y agoI 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/ 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.
- aarpmcgee 9y agoYou can wrap any existing API with graphql https://medium.com/taller-team/graphql-today-using-apollo-for-applications-that-still-depend-on-rest-apis-839895ce20d0 https://medium.com/taller-team/graphql-today-using-apollo-fo...
- exogen 9y ago> 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. 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/d5ddf86dd7f9efd15d3fabdace759abd https://gist.github.com/exogen/d5ddf86dd7f9efd15d3fabdace759...
- otto_ortega 9y agoYou make it sound pretty easy, I will check on that example for sure.
- petetnt 9y agoGraphQL 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. [0] https://github.com/postgraphql/postgraphql https://github.com/postgraphql/postgraphql [1] https://github.com/motleyagency/devday-tutorials/blob/master/docs/02_graphqlify.md https://github.com/motleyagency/devday-tutorials/blob/master...
- akmiller 9y agoThis is why Om Next (in cljs) with datomic backend is so powerful!
- erichmond 9y agoI 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.
- akmiller 9y agoIt is, but if you are going that route and have not chosen a client side framework then Om Next is a better fit on the client for this type of setup.
- sorenbs 9y agoThat's exactly right. GraphQL is a contract between backend and frontend. I tend to think of the GraphQL schema as documentation that is always up to date.
- exogen 9y agoOne 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. Consider this query from the article: query ProfilePageData { user(handle: "manifoldco") { ...HeaderData ...SidebarData ...TweetListData } } 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.: query ProfilePageData { user(handle: "manifoldco") { ${userFragments} } } ...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 https://github.com/exogen/apollo-dynamic-queries
- atticusberg 9y agoIt 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.
- exogen 9y agoI've considered that, but it's extremely annoying (and still not really possible with Relay or Apollo). Not only would I be relying on Apollo's query batching/merging in order to not make 100 different queries over the network, but each child component would need to duplicate the base query and variables, meaning they'd need the props that correspond to query variables passed all the way down the component tree to them. Consider the Artist.Name and Artist.Disambiguation components in my GitHub example. Notice how they don't need the `mbid` prop that the ancestor component provides. I want a component like that for every single field in my Artist schema. If every one of those components duplicated the artist query, they'd all need to be passed the `mbid`, because that's how it determines what artist to retrieve. It's possible to do some tricks with `context` like I'm doing now, but I don't really trust that it's a better solution than having one query execution point with an extendable query.
- kotojo 9y agoQuestion 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?
- mattbessey 9y agoApollo 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).
- brokentone 9y agoIt'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.
- mattmurdog 9y agoThe one thing I never got with GraphQL is what do you query if you don't know what to query for??? Can someone answer this for me. 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?
- epidemian 9y agoUsually 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/ http://graphql.org/swapi-graphql/
- exogen 9y agoThe 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 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.
- jmull 9y agoI 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.
- ojr 9y agoI 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
- avodonosov 9y agoom.next does a similar thing