Hacker News new | comments | show | ask | jobs | submit login
How GraphQL Replaces Redux (hackernoon.com)
80 points by gregorymichael 38 days ago | hide | past | web | favorite | 58 comments



GraphQL is a convention on communication, like REST. Redux is a way to manage application state. They are apples and oranges. You could ostensibly feed a Redux store with GraphQL.

This post is like all the others that tout, "moving from X language to Y saved us $3,000 per month on AWS" – it's usually not the transition from one tool to another, it's the fact that you rewrote your application with more knowledge and insight into the problem and have simply done a better job. Or in this case, a misuse of Redux led to a transition to GraphQL which painted Redux in a poor light.

There still isn't a compelling solution to problems like this... Apollo certainly isn't it. I want to feed GraphQL & REST into a central datastore in my application (be-it a Web/SPA/Browser app, or a local app) and abstract away the guts. A lot of devs are leaning on GraphQL for small experimental apps, fetching data in their components and violating every rule in the book on SRP and SOLID. It works for MVP's and hobby projects, but when you have a larger team, userbase, etc... the abstractions become critical.

We, as an ecosystem, need to focus more on those abstractions and not on the one-size-fits-all buzzword tooling. Server <> Datastore <> Application, not Server <> Application with the library of the week bolted in.


So this apple/oranges thing is true and addressed in the article. Have you used GraphQL/Apollo? It can do a lot of the things you're wanting: - You can combine multiple data sources into a central datastore using GraphQL (REST APIs + DB queries etc.., that's one of the major benefits of it. - Apollo on the client can manage local state as well as server state in one standardized interface. - GraphQL is great for MVPs and Hobby projects but is used for a larger projects as well (Shopify, Github, Coursera, Facebook, Pinterest, Product Hunt, I could go on...).

I'd suggest you give it a shot, it's super fun to work with and isn't going anywhere anytime soon.


A lot of the new work we do at FarmLogs is built with GraphQL. We've been running some critical apps with it and in a lot of aspects its a real joy. That being said, nested HoC's and the way it is used on the web is not ideal. Perhaps we are using it incorrectly there, but the documentation hasn't been a lot of help.

> You can combine multiple data sources into a central datastore using GraphQL (REST APIs + DB queries etc.., that's one of the major benefits of it.

Would love to see the docs on this because I have yet to find it!


I think the GP is referring to Apollo Client 2's ability to abstract over the underlying data source. Their intro blog post for the 2.0 announcement gives a good overview: https://dev-blog.apollodata.com/apollo-client-2-0-5c8d0affce...


I think they're referring to writing your server-side resolvers, there is no difference between requesting data from a database you own vs an API


Currently writing an app that stores graphql data relationally in a redux store. Persists it, makes it available offline, etc. They work well together


They mention it in the article but forgot the caveat in the title:

  How GraphQL[1] Replaces[2] Redux
[1] Or any well designed back end API

[2] For some narrow, often simple applications. And even in those cases it usually doesn't replace redux as much as it augments it.


Fair points. The thing that tipped in favor of GraphQL for the back-end was that it puts the client in charge of the data structure. I suppose you could hack something like that with REST but it would be difficult. Our application is by no means narrow or simple and GraphQL (without Redux) has been perfect. I don't dislike Redux, we just didn't need it after switching to GraphQL.


Could controlling the shape of the data returned by GraphQL on the client open up your application to really inefficient querying?

We control what is returned in data from our REST API by merely specifying the fields you want as a parameter. If there are use cases that would require multiple tables to be joined, those are created ahead of time as views with appropriate triggers for updates and then endpoints are created for accessing that view through RESTful methods. This has always worked just fine.


Doesn't that lead to an explosion of the number of sql views and backend controllers/endpoints?


Not at all. Not sure what other people are trying to do though.


Being able to stay agile & change the app, without breaking old versions of the app, and without having to have an explosion of ad-hoc end-points for every change you've ever made. With graphQL its perfectly reasonable to never rename or delete fields, and never break backwards compatibility. With REST that would not work & would result in over-fetching, or tons of ad-hoc end points for every query you've ever written.


>I suppose you could hack something like that with REST but it would be difficult.

Not really. You can design specific REST endpoints to return the data in the format you want.


And now your frontenders need to know how to write code in whatever your backend is written in, lest every new change be bottlenecked waiting for someone to build them new endpoints. Also, your backend guys are tied up constantly doing stupid endpoint changes, and both teams are wasting time messing around with extra effort to allow one side to be deployed before the other, instead of working on actual functionality work. Doing this in REST is a genuinely unpleasant experience, well deserving of being called hacky


> And now your frontenders need to know how to write code in whatever your backend is written in

Wat.

Frontenders can write their frontend code in whatever they see fit. REST is a contract on data and format of the data between frontend and backend.

> Also, your backend guys are tied up constantly doing stupid endpoint changes, and both teams are wasting time messing around with extra effort to allow one side to be deployed before the other, instead of working on actual functionality work.

Well, if your teams are dysfunctional, then of course, that's what you will end up having.

Now tell me:

- what will you do when your glorious ad hoc GraphQL query ands up bringing the database to its knees?

- what will happen when your glorious GraphQL schema doesn't have all the data the frontend needs?


> Frontenders can write their frontend code in whatever they see fit. REST is a contract on data and format of the data between frontend and backend.

Oh, it’s a contract? Amazing, I guess that means you can just update the contract and nobody is stuck doing busywork anymore. Nope? I guess then either your frontenders need to learn your backend stack, lest they be stuck waiting for someone to do the busywork for them. I feel like I’m repeating myself, because I am. Please don’t quote out of context

> Now tell me: > - what will you do when your glorious ad hoc GraphQL query ands up bringing the database to its knees? > - what will happen when your glorious GraphQL schema doesn't have all the data the frontend needs?

Sound like interesting, challenging, and satisfying problems for the backenders to work on. Certainly more so than adding/removing fields from serialisers. These also seem like much more rare problems than the small data requirement changes that are the backbone of frontend work.

I’d rather work on speeding up the things that slow down development and deal with performance when it becomes a problem. I dunno, maybe our experience differ, and in you world your app is relatively static and performance is crucial, but the world I exist in involves stakeholders constantly wanting minor changes, performance has never been a problem, and development is constantly blocking because of frontend/backend blockers on our “rest” api and capacity on either side being wasted at various times because of that blocking.

Sure, sometime someone’s going to write a horrendous graphQL query where the answer is going to be “sorry, we can’t make that perfomant so we have to disallow it”, but that’s a: solvable and b: going to happen a lot less often than your frontend is going to need an extra field (or no longer need a field, but since nothing breaks these change requests rarely come through and your backend is eternally querying and sending unused data over the wire)


> I guess then either your frontenders need to learn your backend stack

Why would frontenders need to learn the backend stack? Do you even know what REST is?

Riddle me this: what happens when frontend developers need data not exposed by the GraphQL schema? Do the need to learn the backend stuff as well? If not, why would they need that for REST?

> satisfying problems for the backenders to work on. Certainly more so than adding/removing fields from serialisers.

Because GraphQL automagically knows how serialize-deserialize any schema, riiiight.

> but the world I exist in involves stakeholders constantly wanting minor changes

So. How do you deal with those changes? Oh, let me see: you change schemas, you write new serializers/deserializers etc.

> development is constantly blocking because of frontend/backend blockers on our “rest” api and capacity on either side being wasted at various times because of that blocking.

For some reason you blame your failing processes on technology. Fix the process.


- what will you do when your glorious ad hoc GraphQL query ands up bringing the database to its knees?

With REST you can have an N+1 query, but you're making multiple round trips from the client to the server. With GraphQL, you can also write an N+1 query, so you can shoot yourself in the foot either way.

I would probably use graphql-middleware to log the backend calls, or just look at my backend's log, identify the N+1 query and instrument data loader to batch it out. But of course you should load test your app before even shipping it so why would you have this problem unless you do not test?

- what will happen when your glorious GraphQL schema doesn't have all the data the frontend needs?

I can add the field without impacting existing clients that I have shipped. With REST, the old clients would also get the new field.

- if your teams are dysfunctional, then of course, that's what you will end up having.

The point is that your teams can function independently of each other, each focusing more effort on doing their own job & less time syncing with the other team.


> With REST you can have an N+1 query, but you're making multiple round trips from the client to the server.

With REST I can specifically optimise the calls because I know the contract and the possible incoming/outgoing requests.

> I can add the field without impacting existing clients that I have shipped. With REST, the old clients would also get the new field.

Why are so many people discussing REST in GraphQL threads so oblivious of what REST is?

One word: versioning

> The point is that your teams can function independently of each other, each focusing more effort on doing their own job & less time syncing with the other team.

Don't blame your failing processes on technology. There's nothing magical in GraphQL that makes it a magical thing making teams independent of each other. Tell me: what happens when frontend team requests data that's not exposed in the GraphQL schema?


> Why are so many people discussing REST in GraphQL threads so oblivious of what REST is?

Why are you discussing graphQL you're oblivious to the problem it solves. Graphql obviates the need to version, like with REST. Facebook had that problem with 30k react components, their processes are fine. My processes are fine too, you are obviously just biased against graphQL. You can specifically optimize a graphQL query by the way.

Versioning creates an explosion of REST end points in fast changing code bases. GraphQL solves that problem. If you don't have that problem then don't use it. You don't need to insult other people who are explaining the benefits it had in their project. That seems oddly defensive of REST, which is the de facto transport for a GraphQL query (they aren't even mutually exclusive). This comment thread is like arguing what is the better fruit apples or potato. And potatoes aren't a fruit


> Facebook had that problem with 30k react components, their processes are fine.

Ah. The old fallacy of "if it's good for Facebook, it's good for me".

> Versioning creates an explosion of REST end points in fast changing code bases. GraphQL solves that problem.

So. What happens when you change your GraphQL schema to an incompatible one? Just don't tell me a GraphQL schema is magically perfect from the start.

> That seems oddly defensive of REST, which is the de facto transport for a GraphQL query (they aren't even mutually exclusive).

It's not defensive. It's questions about the reality of things that every and all GraphQL proponents dismiss and brush over.


I did not say that. That's a straw man. If you have the same problem as Facebook it is useful to consider the same solutions. No one is saying that all projects have the same problems as Facebook

You can still technically version a graphQL API just the same as with REST. I haven't heard of anyone having to do this. In practice you add new fields and stop using old ones incrementally.

The biggest benefit is a front end developer can mock up a new UI without waiting on a new backend endpoint. You can a/b test many variations of your UI without a plethora of ad hoc end endpoints


> Why are so many people discussing REST in GraphQL threads so oblivious of what REST is?

It's on purpose. You can see it how Graphql is marketed in tech meet-ups. The proponents always argue against strawmen. I find it disgusting.


Well, that's why I work with full-stack developers who can do both changes at the same time.


I've been using Apollo Client and React to manage state on a medium size React app (i.e. no Redux). Interested to hear your thoughts here. Have you been using Redux + Apollo Client + React on a medium to large app?


I've only used GraphQL (with Relay) on fairly large apps but in my experience the number of apps that don't benefit from some sort of client side state management tends to fall into a very small window.

Introducing state management doesn't come for free, of course. That is an extra layer of complexity that you have to reason and maintain. And if your app doesn't need any client side caching or you don't envision a need to have shared state between your components maybe you don't need to have something like Redux. But I feel like the use cases for those sort of apps tend to be pretty narrow.

edit: Another commenter mentioned a good point that gets to the heart of your question better than my rambling -- You are still managing state in your app - just with Apollo instead of Redux.


That's not GraphQL replacing Redux - that's Relay (ie, Apollo) replacing Redux.

So yes, you can replace Redux with something different. There are pros and cons to it, but it's not required or even fundamental to implementing GraphQL in a React app


What about client side state? Form validations? Any sort of user input before it's being sent to the server. You also may need ways to handle persistence or offline use.

There are some new features in Apollo for handling client side state but I'm sticking to Redux for now (for client side state, I am using Apollo for some data fetching).


GraphQL does not replace redux, Apollo sort of does but they solve different overlapping problems.

GraphQL is serializable & a graphQL query or mutation is conceptually the same as a standard FLUX action used by Redux.

The main difference is Redux intends to separate async logic & mutations, to make them easier to reason about in isolation. Apollo intends to remove the need to reason about async logic. In Apollo, you still have to deal with state mutations by refetching everything after any change, or writing verbose cache invalidation logic. So both Redux & Apollo make you reason about state mutations.

Apollo-link is like Redux middleware, it uses observables so its like redux-observable middleware.

If you treated Apollo like Redux, you'd have to fire a graphQL mutation as if it were a Redux action. In redux you can ignore an action. In Apollo, to ignore a mutation you would have to write custom apollo-link middleware to handle that action (mutation). As you can see redux & apollo solve overlapping but different problems.

If you are coalescing multiple API responses coming in over time, you may have a need for RxJS, not Redux. That is inherently a stream of events happening over time, so use a streams library (perhaps together with Redux).


I started using the Apollo Universal Starter Kit.[0] They were using both Redux with Apollo GraphQL. This really bothered me because there were two stores. Apollo 2 doesn't use Redux for the cache anymore. I went ahead and first pulled out the Redux dependency using Apollo Link State.[1][2] Then I went ahead and removed the Redux-Form dependency using Formik[3] instead.[4] The project maintainers thought it was a good idea and removed Redux and Redux-Form dependencies from all the packages. If you are looking for a way to not use Redux with Apollo, it has been solved. Although Apollo Link State requires some more code, it does normalize the data which means selectors are not needed which is a nice way to think about the data.

[0] https://github.com/sysgears/apollo-universal-starter-kit

[1] https://github.com/apollographql/apollo-link-state

[2] https://github.com/adam-s/apollo-universal-starter-kit/commi...

[3] https://github.com/jaredpalmer/formik

[4] https://github.com/adam-s/apollo-universal-starter-kit/commi...


The title is a little click-baity, but if I have it right, the OP is saying that: because you can control the shape of your data on the client (graphql) you don't have to write code to wrangle your response data into the shape of your react component's properties (redux).

Which kind of makes sense, but I'm more biased towards thinking you'd almost always need some client-side work to reshape the response data because the front-end will always evolve at a different pace to the graphql endpoint, which ultimately has to be implemented by the server. Unless the entire team reaches this amazing point where the "graphql schema" and the abstractions in the app are just always in sync. Isn't it?

(Also, I love redux. Almost can't imagine using react without redux for any application. I started using react unreservedly, because redux. After disastrous attempts at flux. Redux is not going away I think.)


This is true. Our team is a little unique maybe in that we can all modify the GraphQL Schemas when we need to (we're using Node.js + Join Monster so it's all JavaScript). I would say though that with our REST API, updating was a lot more involved as we'd have to add more boilerplate on the client side to support the new data structures, whereas with GraphQL, it's just updating the query.


Sounds like you could have made your feed items REST API return the top 3 comments as well...

Maybe the lesson here isn't that GraphQL is a magic bullet, but that designing your API for your business needs solves a lot of frontend complexity (even if it's not pure "REST").


That's true however at that point our API is not longer "RESTfull" and become very ad hoc. The cool thing we found with GraphQL is that the client can control the shape of the data it needs without any server side changes (assuming your schema exposes everything properly).


> The cool thing we found with GraphQL is that the client can control the shape of the data it needs without any server side changes.

This is the single biggest advantage of GraphQL and AFAIK one of the main reasons for it's conception.


> That's true however at that point our API is not longer "RESTfull" and become very ad hoc.

So.... That's why you decide to create ad-hoch APIs using GraphQL queries instead: "the client can control the shape of the data it needs"


Why is returning say the three top comments not RESTful?


Because in rest, urls are supposed to specify a resource, but now your response is a resource and some other resources too.

Not saying that being pure to rest ideology is a good thing. I think it’s a terrible fit for most applications more complex than a demo todo app


There's nothing "impure" about that. From Fielding's dissertation (emphasis mine):

"The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on."

By the way, REST is not an ideology, it's an architectural style. It defines a set of constraints, and specifies the advantages and disadvantages of applying each of them.


Seems like you were just using Redux incorrectly.


What protections can you put in place to limit the client query?

It seems with an appropriate GraphQL query it would be possible to generate significant data retrieval server side.


The graphql tutorial has a chapter devoted to this: https://www.howtographql.com/advanced/4-security/

In a nutshell, you can limit the depth to which a query will resolve in order to prevent abuse. You can also go much further and whitelist a specific set of queries (which comes with some additional bandwidth wins!) See https://dev-blog.apollodata.com/persisted-graphql-queries-wi...


Redux is useful, just not as a primary store for model data.

For example, Found (https://github.com/4Catalyzer/found) uses Redux to keep route state. It's nice to use Redux in that context, because route state is global but also simple, not very hierarchical.

But for model state, Found integrates with Relay (https://github.com/4Catalyzer/found-relay/), because, as this article says, GraphQL reduces a lot of the REST/UI impedance.


For a better introduction on how Apollo v2 (the graphql client) could replace redux, read this: https://dev-blog.apollodata.com/the-future-of-state-manageme...

I’ve personally tried it (with special attention on its capability to manage local state) and it did work out pretty well, with a lot of redux boilerplate code eliminated and a more effecient workflow, better yet, now you just need to learn one graphql syntax to rule them all.


TL;DR click bait. The author is replacing Redux with Apollo - a client side graphql library that HAS BUILT IN STATE MANAGEMENT, which he fails to differentiate or mention... Apollo is similar to the firebase event / subscription model.

https://dev-blog.apollodata.com/tutorial-graphql-subscriptio...


Did you actually read the article? I explicitly mention that Apollo uses Redux as a cache under the hood (although that's not required).


I reread it several times trying to understand how simply using GraphQL allowed you to eliminate the need for all actions / stores for your entire client side stack. It wasn't until I looked into Apollo that I understood what you had actually implemented.


Apollo is mentioned 4 times in the article. That's beside the point though, even using GraphQL with plain old HTTP requests would have removed a lot of the need for Redux in our case.


Just an fyi, Apollo no longer uses Redux under the hood.


Question for Apollo Client users.

I've been using Apollo Client. When I add or delete data, I need to update the local store on Apollo.

How have you found your experience using the local store on Apollo versus Redux?


Since version 2.0, Apollo Client no longer uses Redux. A large application I am currently working on uses both Redux and Apollo. They are two tools that serve different purposes, Apollo just happens to have built-in state management, an important feature that provides the ability to compose components directly from query HOC's and their children from their fragments. That said, these components inherit their state from Apollo, but many of them also share overall state with Redux. As far as creating and deleting data, I'm assuming you're referring to updating Apollo's cache, primarily collections? My mutation payloads provide the fields necessary to update the cache in a way similar to a re-fetch. When you perform a re-fetch, you're simply updating the cache, so why not just do it in one query -- as the result of your mutation. For example, let's say I have a query that provides a collection and I call a mutation that adds or removes an element. The mutation payload fields will simply re-query that collection, and once Apollo sees that response, it will update its cache accordingly. Apollo's API also provides some very nice methods for fine grain control over its cache. Another important feature that helps update your cache upon change are subscriptions, which of course have plenty of other benefits.


The local store in Apollo (at least the current version) is actually Redux (and a good use case for it IMO). In our experience it hasn't been to hard to manage and it's nice that you can still use the Redux DevTools to inspect the state.


I don't think it is anymore, latest version depends on a custom cache implementation which does not seem to be based on redux.


I wish that was still the case.


I'm a bit lost. Aren't they two different things? One is a DSL for APIs, the other one is a state manager.


actually, apollo-client is building in support for REST, so you will be able to use apollo-link-state with your restful api AS WELL AS your graphql api.

That's the true "replaces redux" statement.


Will you make a fresh HTTP request every time the client needs to render a component? You could persist data client-side to make things more efficient. It would be best to use a state container to manage this. Maybe something like Redux?


Naively, yes, but in practice this is one of the things a good graphql client library can solve. Apollo Client, for example, will bundle query fragments from all your components together into a single request, and manage caching under the hood for you.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: