react-boilerplate / react-boilerplate

🔥 A highly scalable, offline-first foundation with the best developer experience and a focus on performance and best practices.
https://www.reactboilerplate.com
MIT License
29.48k stars 6.12k forks source link

GraphQL client #1041

Closed sedubois closed 5 years ago

sedubois commented 8 years ago

Facebook's GraphQL appears to me a natural choice of backend protocol for new React projects vs. REST. Within the React ecosystem, it moreover goes nicely with Facebook's Relay, Meteor's Apollo or other client libraries to provide modern UX and DX.

Although it is of course possible to just let the developer call their GraphQL API within a Redux saga, it seems natural to replace Redux with Relay/Apollo/other (also in order to use all current and upcoming features such as caching, optimistic updates, realtime/subscriptions, etc). Apollo actually uses Redux under the hood and documents how to interoperate with an existing Redux store. It means an opinionated restriction of the backend protocol to GraphQL, but that appears in line with the doc: "start your app with our community's current ideas on what represents optimal developer experience, best practice, most efficient tooling and cleanest project structure."

Conveniently, GitHub just released a GraphQL API, so the example could be updated with it.

Is the choice of redux(-saga) set in stone? If not, what do others think of replacing it with Relay/Apollo/other?

peter-mouland commented 8 years ago

I'm hearing more about relay, it's popped up a few times for me recently. is really a replacement for redux? does that mean the whole app structure would change (e.g no more actions/reducers etc)?

sedubois commented 8 years ago

@peter-mouland it appears so, instructions to query the data stay together with the view. No more implicit data dependencies across components (but under the hood is one central normalized graph cache). Of course, Relay and Redux could be used together in more complex apps, similar to Facebook which mentions: "One pattern we see emerging is letting Relay manage the bulk of the data flow for an application, but using Flux stores on the side to handle a subset of application state."

Here's an article mentioning one can well stick with Redux, but that doesn't allow to take advantage of some of GraphQL's key benefits.

sedubois commented 8 years ago

Conveniently, GitHub just released a GraphQL API, so the example could be updated with it.

Correction, that API isn't public yet, requires agreement to pre-release program then using auth token.

sedubois commented 8 years ago

Also, Relay offline/low-connectivity support is not there yet, but clearly a priority according to their 2015 post, 2016 post and roadmap. If that's an immediate requirement, this could be closed for now. Personally I intend to try GraphQL/Relay as I can live without offline in my prototype.

mxstbr commented 8 years ago

I love GraphQL and Relay, I absolutely agree that they highly likely are the future of APIs.

The issue I have is that it would make react-boilerplate only feasible for projects that don't have an existing API and/or are willing to make the jump to GraphQL. I'm willing to bet that that's a pretty small percentage of them, and right now, I'd much rather focus on getting the frontend part 100% right for APIs of any kind and not be tied to any specific backend system.

That being said, I'll happily discuss more about this! Convince me, why should react-boilerplate switch to a GraphQL/Relay setup by default?

sedubois commented 8 years ago

Alright I'll take a chance 😉 I could flip around the argument of jumping to GraphQL: why would new projects, even those already having REST or other APIs, invest in learning and maintaining Redux, Redux-saga, etc, instead of GraphQL/Relay, which seems a more powerful and promising technology?

If we agree GraphQL is the future, shouldn't this boilerplate help projects be part of this future for months and years to come instead of pushing them in the "wrong" direction?

How about providing a minimal GraphQL backend within this boilerplate? Backend devs would have the flexibility to add their own code to plug into existing REST APIs and gradually migrate their code, while frontend devs would have direct access to state of the art DX/UX.

FYI, react starter kit (>10k stars) demoes a GraphQL backend. In choosing between the 2, so far I chose this one for its frontend focus (to balance my primarily backend experience), but I actually saw RBP's state and backend management as weak points. Hence opening this discussion.

sedubois commented 8 years ago

Besides the "REST vs. GraphQL" discussion, remember that the choice of GraphQL primarily benefits front-end devs! It enables them to query the data in exactly the way they want it presented, right beside their views, together with static type checking and linting, plus all of the existing and upcoming optimizations. That should support your vision of optimal UX/DX.

mxstbr commented 8 years ago

I'll have to think about this, it's an interesting direction.

Not convinced this is something we want to do just yet, but I'm now pretty sure it'll happen eventually…

sedubois commented 8 years ago

Yes I get you. If you have further thoughts/insights about this or some experiment to share, I'd love to hear back! Also at least when Relay 2 comes out, we should reconsider.

jwinn commented 8 years ago

Please correct me if I am wrong, but doesn't GraphQL require the app to have some form of NodeJS (web) server, removing the ability to have the app hosted statically (e.g. CDN)? The ability to just deploy to a CDN (or non-NodeJS server) is one of the reasons that initially brought me to this project.

However, I feel this issue can be mitigated with a proper CLI for RBP that allows one to choose features, i.e. static, SSR/GraphQL, etc.

@mxstbr do you know, off-hand, the Issue/Feature # for the CLI work, if there is one? :-)

mxstbr commented 8 years ago

However, I feel this issue can be mitigated with a proper CLI for RBP that allows one to choose features, i.e. static, SSR/GraphQL, etc.

I'm not sure this is going to happen in the way you're imagining – I don't really want to maintain multiple codebases at the same time, that's a big pain. (we've been doing that for generator-keystone and it's the worst)

That being said, the issue number is #180.

jwinn commented 8 years ago

I'm not sure this is going to happen in the way you're imagining – I don't really want to maintain multiple codebases at the same time, that's a big pain. (we've been doing that for generator-keystone and it's the worst)

Completely agree-I'd prefer not to maintain separate codebases. I was just trying to think of a way to offer GraphQL and Relay/Apollo in lieu of not wanting to lose the static deployment aspect of RBP. Again, if I'm wrong in the assumption-which was the case last year-that GraphQL requires Node to run, please let me know.

sedubois commented 8 years ago

One potentially really cool thing, would be the ability to hot-reload the frontend code upon backend schema changes. It's technically feasible with babel-plugin-react-relay, but a graphql bug prevents from having it working (npm prune and npm dedupe didn't help). Thanks @schickling for troubleshooting!

So right now I first make things work by building the schema manually (by manual call to introspectionQuery) and passing it to babel-relay-plugin. Could explore the cool HMR stuff separately.

sedubois commented 8 years ago

@jwinn forgot to answer: of course with GraphQL like any other backend, nothing prevents the frontend from querying another endpdoint than an endpoint provided within this repo, and hence ensuring this repo only provides the frontend. I'm curious though, how does this get deployed to a CDN (which I'm not familiar with) as it does have Node.js code (the express server)? And can you give an example of such a CDN/non-NodeJS server?

So the same way it's (from what I understand) already possible to ignore the backend within this repo and query something else instead, it should be possible to do the same with GraphQL.

mxstbr commented 8 years ago

I'm really looking forward to where this goes 😊

sedubois commented 8 years ago

BTW managed to use babel-plugin-react-relay as documented here: https://github.com/graphcool/babel-plugin-react-relay/pull/11

This opens the possibility of HMRing the frontend upon backend schema changes and having on-the-fly type checking. (NB: don't know what Apollo is capable of to compare.)

jwinn commented 8 years ago

@jwinn forgot to answer: of course with GraphQL like any other backend, nothing prevents the frontend from querying another endpdoint than an endpoint provided within this repo, and hence ensuring this repo only provides the frontend. I'm curious though, how does this get deployed to a CDN (which I'm not familiar with) as it does have Node.js code (the express server)? And can you give an example of such a CDN/non-NodeJS server?

RBP does have a NodeJS server (Express) but it's not required. Just npm run build and copy/deploy the contents of the build folder over to a CDN, (shared) hosting provider, Apache server, application server, etc. As it's just static content (HTML, JS, CSS, etc.), there is no Node environment required--outside the build process--any web container will do. React, redux(-saga), react-router, etc. do not require a Node backend, so this affords flexibility in how the project is used and deployed.

Correct me if I am wrong (as I haven't checked in over a year), but GraphQL must be run in a Node environment. Under this assumption, switching to GraphQL and Relay/Apollo, in lieu of redux-saga (and reselect), would remove the static deployment--via npm run build and deploy--ability of the boilerplate. Sure, where static deployment is needed, GraphQL could be removed, but then what would one add for managing the API (e.g. GitHub) interaction and side effects, redux-saga or some other flux-(like) implementation?

Again, I am not inherently opposed to switching. I just want to make sure this concern/consideration is taken into account when determining to overhaul an, arguably, important piece of the boilerplate. :-)

sedubois commented 8 years ago

@jwinn as mentioned, the GraphQL client code can access a public API outside of this repo, just like right now it accesses the GitHub public REST API. No intrinsic need for Node.

jwinn commented 8 years ago

@sedubois That was the key crux of the assumption. If GraphQL can run entirely client-side, then static deployment is a non-issue. Like I said, the last time I checked (over a year ago) GraphQL required a node environment to work effectively.

sedubois commented 8 years ago

@jwinn I think there's a confusion between client and server here. Of course GraphQL clients don't need Node, or they wouldn't be clients.

jwinn commented 8 years ago

@sedubois To alleviate any perceived client/server confusion, in this discussion, for all intents and purposes, Relay/Apollo are GraphQL clients, correct?

TL;DR

My concern is related to baking the GraphQL server into the boilerplate. Currently, in the boilerplate, API implementation is left to the developer leveraging the boilerplate. If a GraphQL-based solution can be run (deployed) entirely without NodeJS (outside of the build process), then the concern is no longer valid.

@mxstbr If, from RBP's perspective, the ability to provide deployment of an app into a non-NodeJS web environment, is not required, please let me know.

I am arguing neither for nor against GraphQL, as I think GraphQL can have huge upsides. Also, I feel GraphQL and Relay/Apollo are being conflated here. Neither necessarily, requires the other. Substituting redux-saga(/reselect) for Relay/Apollo should be its own conversation. With another conversation discussing whether a GraphQL server should be a reference implementation on the backend. If there is no intrinsic value of switching to Relay/Apollo, without using a GraphQL server, then, I think, this is where the confusion, if any, in the conversation, is stemming from.

Also, a PR would be appreciated to show how Relay/Apollo (and GraphQL if required) would work in the boilerplate. :-D

mxstbr commented 8 years ago

If so, what is the value and does the value still exist if GraphQL is not utilized on the backend?

This is a good question, I'd like to know that too.

Can all of this be deployed to a non-NodeJS web environment (e.g. Apache, IIS, Application Server, CDN, etc.)?

As far as I know, there are GraphQL implementations in other languages, but depending on the above answer there might not be a static build anymore like right now.

If, from RBP's perspective, the ability to provide deployment of an app into a non-NodeJS web environment, is not required, please let me know.

I'm not sure. Currently, this is possible because we were always focussed on the frontend side of things. I don't know yet if I want to change that, to be completely honest.

Also, a PR would be appreciated to show how Relay/Apollo (and GraphQL if required) would work in the boilerplate. :-D

I agree, but obviously I don't want anybody to do any "useless" work. (though I would hardly call maintaining a fork of this boilerplate that has Relay/GraphQL baked in useless 😉)

sedubois commented 8 years ago

Yes yes, gimme a sec to learn this stuff 😉 something like this: https://github.com/mxstbr/react-boilerplate/pull/1065

I propose to discuss any backend stuff separately, and that could be a non-existent discussion, as PR shows. In the spirit of serverless apps, people could use GraphQL backends-as-a-service which are popping up like graph.cool, reindex.io, scaphold.io, dgraph.com, RethinkDB's horizon.io (OSS; GraphQL coming in next version)?

Relay/Apollo are GraphQL clients, correct?

yes

Can [a GraphQL client webapp] be deployed to a non-NodeJS web environment?

yes

what is the value and does the value still exist if GraphQL is not utilized on the backend?

YMMV but in broad strokes, GraphQL is an improvement upon REST (e.g 1, 2, 3).

If you need to use a REST API, you can wrap it client-side like here. Maybe Apollo's graphql-anywhere would also be interesting. And this video aims to show that any backend can be converted to GraphQL quickly (in "30 min" 😉).

scf4 commented 8 years ago

Ha...thanks for this. After some research I've decided to scrap a bunch of work and start again with Apollo in RBP. It seems like it should be pretty straightforward to drop the Sagas and add in Apollo.

My only concern now is SSR, is it at all feasible with this boilerplate?

sedubois commented 8 years ago

@scf4 I think isomorphic-relay provides that. I'm not very familiar with SSR in general, and I was also wondering, how is SSR provided when deploying on a CDN?

Could you also briefly explain your choice of Apollo as GraphQL client?

scf4 commented 8 years ago

You would host all your assets on a CDN, but render the initial HTML on the same server as your API (rather than serving empty HTML on the CDN and waiting to load data from the API server).

I don't know whether Apollo or Relay would be best for React Boilerplate in the future, but since adding Apollo to a project seems trivial (and they're essentially feature-equivelant) it seems to make the most sense for me. It uses Redux under the hood (and can connect to your store) unlike Relay which seems to require a lot of fundamental changes to your stack.

sedubois commented 8 years ago

In this PR I added Relay: https://github.com/mxstbr/react-boilerplate/pull/1065 and so far it works...

About CDN, the "problem" is that you don't necessarily have an API server at all. For example right now I experiment with Graph.cool which serves as my only backend. I added a feature request to have SSR in there, who knows.

acamarata commented 8 years ago

Apollo seems the better choice in relation to Redux concerns and features. Why would we want to use Relay instead of Apollo?

sedubois commented 8 years ago

@alisalaah so far I went with Relay basically for the reasons outlined in the conclusion of this article, but I haven't properly evaluated Apollo myself. That might change when trying to integrate some GraphQL CMS backend such as Relax which is nearing beta. That one provides its own GraphQL client, Relate.

I think the main point right now is to bring attention to GraphQL APIs in general. The choice of GraphQL client in particular to choose on the front-end, or which data/content GraphQL server to have on the back-end, doesn't need to be set in stone. These things would be decoupled.

sedubois commented 8 years ago

@alisalaah I tried to integrate Apollo, but encountered issues like 1, 2, 3. E.g there's no data masking, this comment shows it's quite complicated to get fragments working (I just gave up trying), and need to manually handle loading cases. Contrary to what the docs led to believe, I have the feeling Apollo is not so mature and found it easier to integrate Relay (see https://github.com/mxstbr/react-boilerplate/pull/1065) and I even have time travel working as before. Just didn't try sagas (don't want to use them), but I guess should still work as well.

sourcesoft commented 8 years ago

Things I like to happen with RBP

  1. Client-side by default and then have a simple SSR option or branch I could merge. It didn't have to be the best implementation of SSR but one that doesn't lose any benefits of client-side version (there are problems with CSS, assets and routings. And yes I love styled-components).
  2. It would be awesome to finally migrate to GraphQL no matter client or SSR. There's no doubt about benefits of GraphQL over REST and I think this boilerplate needs to show the best practices. All API Backend frameworks are supporting it out of the box and I guess it's time to seize the moment.
  3. The choice between Redux(with graphql) and Relay(which I don't have any experience with) pops up a question for me: There's more than just data flow to a client app; state management. Using Relay how can I deal with complex UI interactions or forms(redux-form is an awesome redux equivalent)?

Remember the opinions comes from a person who just learned GraphQL and haven't had an actual experience with it and just knows the benefits.

scf4 commented 8 years ago

It seems like Relay 2 may be exactly what we need. I just have no idea when it will be released.

scf4 commented 8 years ago

https://github.com/facebook/relay/issues/1369

sedubois commented 8 years ago

@sourcesoft @scf4 I am indeed curious to get my hands on Relay 2.

Meanwhile (and maybe/probably later too), redux-saga remains the way to manage state (as in this example visible here that @mxstbr mentioned) and IMHO GraphQL clients could already take care of data fetching, if we demonstrate it mixes well with redux-saga.

mxstbr commented 8 years ago

I'm becoming more convinced we should integrate GraphQL and Relay, but still keep Redux and redux-saga for state management and long running transactions. What do you think about that?

sedubois commented 8 years ago

Yes sounds good @mxstbr, just need to build a compelling example... Maybe guys you can give feedback on https://github.com/mxstbr/react-boilerplate/pull/1065. Also I experimented with Apollo on top of that: https://github.com/sedubois/belong/compare/gql...apollo but encountered https://github.com/apollostack/react-apollo/issues/267 (also noticed the limitations https://github.com/apollostack/react-apollo/issues/262 and https://github.com/apollostack/react-apollo/issues/268 vs Relay).

scf4 commented 8 years ago

What are the reasons to keep redux-saga if Relay handles data fetching?

And how do you feel about the advantages of Apollo listed in this article and the update linked in the first paragraph?

mxstbr commented 8 years ago

What are the reasons to keep redux-saga if Relay handles data fetching?

I don't use redux-saga for data fetching reasons. I use it for any sort of asynchronous thing that happens in my application. (which does include data fetching, but with Relay just wouldn't include data fetching anymore)

I believe this is one of the best examples of redux-saga. There is no data fetching whatsoever happening, it's just an onboarding flow – but it's beautiful to read while your main application stays clean. (imagine all of that being done in the main app somewhere, ugh)

In my mind, sagas are like a separate "thread" of your application. (not a literal thread, just a mental model) You have your main application, and you have another thread for async stuff. (whatever that may be) Those two "threads" only ever communicate via redux actions.

Thanks to react, our main app thread doesn't have to care about anything. It just fires a redux action to say "Hey, something happened" – and then the saga thread may do something with that, or it might not. In any case, sometime later, something happens on the saga thread, so it fires off a redux action to tell the main app thread to do something. (e.g. render something new) Our main app thread stays completely clean and functional, and all the async stuff is delegated to an easy-to-read-and-test saga.

That, for me, is the beauty of sagas, and why I haven't yet switched to GraphQL/Relay – they just can't do that, while data fetching with them is arguably far the better way than AJAX/REST. So let's combine them!

sourcesoft commented 8 years ago

I believe this is one of the best examples of redux-saga. There is no data fetching whatsoever happening, it's just an onboarding flow – but it's beautiful to read while your main application stays clean. (imagine all of that being done in the main app somewhere, ugh)

I believe I can have the same clean syntax using async/await on top of defining custom Promises. But the fact that sagas have take, fork, cancel,... and can build a mindset of dealing with them as a separated thread in a single place makes it unique. IMHO as long as we have Redux, sagas makes life easier.

I think boilerplates like react-starter-kit are using redux and GraphQL without any Relay or Apolo. It's better to implement GraphQL first and don't ditch Redux yet.

jwinn commented 8 years ago

That, for me, is the beauty of sagas, and why I haven't yet switched to GraphQL/Relay – they just can't do that, while data fetching with them is arguably far the better way than AJAX/REST. So let's combine them!

I agree, these (GraphQL and redux-sagas) can co-exist nicely and serve specific roles in an application. For the boilerplate, removing/augmenting the GH REST call with GraphQL (and Relay) would be great to have. Also, GraphQL isn't an "improved" REST, nor is it a ubiquitous replacement. Both have applicable scenarios the other cannot provide. More importantly, the two are not mutually exclusive. Note, I am talking about formal REST, not what some call REST as noted in the FB GraphQL post:

We are interested in the typical attributes of systems that self-identify as REST, rather than systems which are formally REST.

schickling commented 8 years ago

Sorry for off-topic but I couldn't find any contact details for @jwinn. Could you send me a quick email elaborating a bit more about the use cases where you see REST to be superior to GraphQL?

Dattaya commented 8 years ago

I've integrated Apollo into this repository, to be more precise, a modification of it—without Immutable.js. Everything is in this commit: https://github.com/Dattaya/react-boilerplate-object/commit/47ea450f5744e6cf1f5a88c0d3b03fcc8f4b235e This is what has been done:

Let me know if you want to port some parts of it back into this repo. I would love to get some feedback because I'm also new to GraphQL.

Dattaya commented 8 years ago

implement GraphQL first and don't ditch Redux yet

Apollo relies on Redux and you can see whatever it is doing in redux-devtools: apollo-redux-devtools

That doesn't mean that I promote Apollo though, I'm just experimenting with different GraphQL clients. BTW, in addition to Relay, Apollo, Relate, and Lokka, there is also Cashay—https://github.com/mattkrick/cashay

sedubois commented 8 years ago

@Dattaya looks great! It's nice to see a working RBP + Apollo demo compatible with all the rest. I added some comments on your code, only to be taken into account if you were to submit a PR of course. General message: let's minimize the impact (to ease review and limit risk; things could be removed/added later as needed):

NB: hopefully we'll learn more about the future of GraphQL clients next week after the GraphQL Summit...

@mxstbr what do you think?

schickling commented 8 years ago

Thanks for your thoughts and mentioning Graphcool, @sedubois!

most importantly, graph.cool is not yet in general availability

It will be soon! Additionally, we'll soon roll out support for schema files which allows you to setup a GraphQL backend based on a IDL file like the following (reduced Instagram example):

type Post {
  description: String!
  imageUrl: String!
  comments: [Comment!]!
}

type Comment {
  text: String!
  post: Post!
}
Dattaya commented 8 years ago

@sedubois, thank you for your feedback and your comments. @mxstbr wanted to go with Relay and so do I, because it has more contributors and Facebook has more talented developers and resources; it's just Relay 1 is too heavy, 114068 bytes gzipped (React included) and probably too complicated for simple and some medium complexity projects. I hope Relay 2 is better in this regard.

don't remove saga machinery

redux-saga is there, just didn't want to leave an empty file. As you said, something else should be added to showcase it.

sedubois commented 8 years ago

@Dattaya agreed. About sagas I misread the code (e.g when seeing this deleted).

We could either go with Apollo and migrate to Relay 2 when appropriate, or wait for Relay 2. But why wait if Apollo already works well enough? (just thinking out loud here). I also tend to prefer Relay.

cartogram commented 8 years ago

+1 for Relay. Reindex too

acamarata commented 8 years ago

Since mentioning Graphcool and Reindex I thought I'd chime in with Scaphold.io which has the best free tier and a good API.

On Thu, Oct 20, 2016 at 1:48 AM, Matt notifications@github.com wrote:

+1 for Relay. Reindex too

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mxstbr/react-boilerplate/issues/1041#issuecomment-254905736, or mute the thread https://github.com/notifications/unsubscribe-auth/AAQ9ltissWItUWACIgNRtAg6bagYSkLJks5q1mYOgaJpZM4KGqWr .

Dattaya commented 8 years ago

We could either go with Apollo and migrate to Relay 2 when appropriate, or wait for Relay 2. But why wait if Apollo already works well enough? (just thinking out loud here). I also tend to prefer Relay.

I'll wait for @mxstbr decision before sending a new pull request. This is how a request to GitHub GraphQL API would probably look like:

query { 
  repositoryOwner(login: "mxstbr") {
    repositories(first: 30) { # Github limits the max value of loaded entries at once to 30
      edges {
        node {
          path          
          url
          issues {
            totalCount
          }
          isFork
          parent {
            path
            url
          }
        }
      }
    }
  }
}

It gives the following result:

{
  "data": {
    "repositoryOwner": {
      "repositories": {
        "edges": [
          {
            "node": {
              "path": "/mxstbr/old-blog",
              "url": "https://github.com/mxstbr/old-blog",
              "issues": {
                "totalCount": 0
              },
              "isFork": true,
              "parent": {
                "path": "/poole/lanyon",
                "url": "https://github.com/poole/lanyon"
              }
            }
          },
...

Since at least for now you don't want a GraphQL server, it's going to be really easy to migrate to Apollo (I think same true for Relay)—add apollo client and this query, remove data loading with sagas, adjust tests and that's it. Later we can add "load more" button or load more data as the user scrolls.