
GitHub client built with React, Apollo, GraphQL - rwieruch
https://github.com/rwieruch/react-graphql-github-apollo
======
headcanon
I'm currently rewriting our company's customer-facing web app with this stack,
as well as the GraphQL backend. I have to say its an amazing experience so
far. IMO it greatly helps facilitate readable and maintainable code, on both
ends of the stack. Having a strict, self-documenting contract between frontend
and backend is the biggest selling point for me.

Coming from a heavy-client implementation using backbone models, or in another
instance Ember Data with JSON-API, React+Apollo feels like a breath of fresh
air, and simplifies my life to the extent that I wonder why I get paid so much
to do what I do.

I would suggest looking at Github's API explorer
([https://developer.github.com/v4/explorer/](https://developer.github.com/v4/explorer/)).
You can assemble graphql queries in there, inspect the results, and copy/paste
the exact query into an Apollo component to make your own app.

REST is still a bit simpler to implement on the server side but once you have
the GraphQL API built it is infinitely more maintainable when you're working
with multiple teams, and API consumers, each with their own needs and focus.

One weakness I've observed is that since each attribute of an object can make
its own DB query, you can have a situation where a single GraphQL query can
create dozens, or even hundreds, of individual DB queries, creating a
performance issue with a naive implementation. This is mitigated with
libraries that batch requests transparently, or with clever structuring of
your schema that groups similar attributes into one query.

Also, tree-like data structures are not well supported (like a comment thread,
where comments can have replies that recurse infinitely. GraphQL straight up
doesn't do that)

However I think that the benefits outweigh the weaknesses considerably.

~~~
tannhaeuser
> _REST is still a bit simpler ..._

I don't want to take away from your main point, but I wish at least on HN we
could use the term "REST" with its proper meaning, but maybe it's a lost
cause.

REST has nothing to do with JSON-over-HTTP or pretty endpoint URLs. REST and
HATEOAS is about minimal, stateless coupling of web clients and server apps.
The idea is that you point your browser at an endpoint, and the user/browser
drives forward every further interaction and state evolution by hyperlinks and
other affordances presented in the return "representation" (eg. HTML).
Specifically, the web client isn't supposed to do requests against out-of-band
provided URLs for JSON or other payloads with hard-coded endpoints.

I know it might not be a realistic application model for what the Web has
evolved into today, but misuse of the term REST has frustrated its inventor
since at least 2008 [1].

Edit: as discussed many times here eg. [2]

[1]: [http://roy.gbiv.com/untangled/2008/rest-apis-must-be-
hyperte...](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-
driven)

[2]:
[https://news.ycombinator.com/item?id=3635085](https://news.ycombinator.com/item?id=3635085)
\- _Nobody understands REST or HTTP_

~~~
gr__or
I hear this a lot but I think the point is moot. It kind of reminds me of
communists telling me that real communism has never been tried.

Okay okay I know, analogies are sinful. Sorry! My point is that this pure
definition of REST doesn't conflict with what the parent comment outlined. I'd
go even further and say that to implement in this purer, Content-Type
agnostic, state-evolution by hyperlinks kind of way makes the implementation
even harder (around as hard as it is to implement a GraphQL endpoint).

------
throwaway66666
I have 2 very naive questions about graphql. I am not trying to poke holes or
antagonize, I just want to learn.

1\. First one is, if graphql is a query language - why not use an existing
query language that many people are familiar with already? Eg instead of doing
"query{ users(limit: 10) }" why not just send in the request's body "SELECT *
FROM users LIMIT 10;" Or an ORM like query and have the server execute that
(after of course parsing/sanitizing/normalizing it first)?

Why do we need one more ORM like language/abstraction on top of already our
language abstractions? If my backend is in Postgres and ElasticSearch, can't I
just have the client shoot sql and ES json queries instead? Why the new
language?

2\. How does it secure against the client trying to make super heavy queries?
I always find it funny (and it is a good lesson) when an intern writes an
ElasticSearch query that tries to return a 300gb JSON object back to the
browser and crashes everything in the process (not production of course). I
've read that GraphQL has built-in checks for timeouts and query complexity,
but if I am able to write optimized and highly performant SQL is there any
guarantee that the GraphQL layer will output the same results?

~~~
chrisco255
To answer your first question, GraphQL allows the client to safely declare
exactly what data it needs based on the GraphQL schema.

We don't want clients to be able to arbitrarily execute server side SQL
queries, that's dangerous and unsafe. Which is why REST is even used as an
abstraction over the backend in the first place.

The problem with REST is that it's not very adaptable. Any time a client needs
a slightly different payload, either an entirely new endpoint has to be
created on the server side or you have to version the API to handle evolving
use cases.

~~~
throwaway66666
I understand and agree with you with the issues about REST. But I still don't
understand why GraphQL is not unsafe. For example, assuming that we have an
endpoint that returns a list of users but skips banned users. Would I have to
do something like query{user(banned:0)} ? That would be pretty unsafe as well.
So how is graphql different than executing limited queries on the server?

~~~
headcanon
The equivalent REST implementation would be `/users?banned=0`, which would be
equally unsafe if you didn't want clients to view banned users.

In both instances, you would want to implement client authorization, so only
clients with special permissions would be able to execute that query, or would
simply get a different super/subset of users.

I think you're conflating the purposes of GraphQL with that of SQL. GraphQL is
not meant to be a general-purpose, all-powerful, turing-complete query
language like SQL, it is simply a way for clients to specify the exact data
structure they require, based on a server-defined schema.

Authorization issues like you highlighted would have similar solutions under
both implementations, GraphQL does not claim to do that out of the box.

~~~
hungerstrike
Plain old SQL92 is not turing complete. It's just a DSL for working with
structured data. Via [https://stackoverflow.com/questions/900055/is-sql-or-
even-ts...](https://stackoverflow.com/questions/900055/is-sql-or-even-tsql-
turing-complete/7580013#7580013)

SQL could work here but I think GraphQL is better for client apps anyway
because it's based on very easily serialized graph structures instead of a
string of english words that must be parsed. The client and the server can
both work with it much more easily.

I think if you wanted to, you could map SQL onto GraphQL. Someone might have
already done that. The opposite is also very likely already done (GraphQL
mapped to SQL).

~~~
headcanon
somehow I knew someone would call me out on that. HN does not disappoint.

~~~
grzm
Unfairly, in my opinion. SQL92 is not Turing complete, yes. SQL92 is pretty
old, and implementations have definitely added features since then. The more-
upvoted response immediately above the one provided in that StackOverflow
question provides examples of Turing completeness in SQL.

------
RyanShook
What is the consensus on GraphQL? Is it really killing the Rest API or is that
more hype?

~~~
rsanheim
My experience trying to build out the server side backend in GraphQL for
various features was miserable:

* you are adding an additional abstraction layer on top of your data store (in our case, SQL), with significant cost in complexity and speed. This was for queries that served many thousands (or more) of requests a day, btw, so maybe it would be fine for apps w/ just tens or hundreds of users.

* trying to get any complex queries performant was _very_ difficult. We knew how to avoid n+1's w/ SQL and our ORM, but doing so with GraphQL loaders was very difficult and required some very intense promise-based code that was incredibly hard to debug or understand.

* the abstractions felt all wrong - it often felt like our the GraphQL loading layer was completely disjoint from the existing domain model. Building out the GraphQL layer often came at the expense of the domain layer -- maybe this was due to our own inexperience in mixing the two ? Anyway, it felt similar to how impossible it felt to build a decent domain model back in the days of Javabean / EJB frameworks.

That was my experience around a year or year and a half ago, anyways. I
definitely see the value in the declarative nature of GraphQL for client
usage, but the cost on the server side felt _very high_ to make it a reality.

~~~
faitswulff
I've heard GraphQL is a better match for graph databases. I wonder if the
issues you encountered might be a result of that mismatch?

~~~
joshribakoff
Not true per se, the name GraphQL is you are conceptually thinking about your
data in terms of a graph. The underlying data store could be parsing a CSV
file to resolve your data & graphQL still adds immense value.

------
watty
I've had an itch to try GraphQL but after seeing the "doFetchMore()" method
here [https://github.com/rwieruch/react-graphql-github-
apollo/blob...](https://github.com/rwieruch/react-graphql-github-
apollo/blob/master/src/Repositories/index.js) I'm a bit put off.

~~~
rwieruch
Author here :) I used Apollo for the first time in this application, it was
great throughout the implementation, but this was truly the worst part to
implement. It came with multiple flaws in my eyes which are perhaps due to
Apollo being in early stages or me just being inexperienced with it.

\- updateQuery was a deprecated property when I implemented it and one should
use update instead. But it wasn't and maybe still isn't possible to use update
for the fetchMore scenario.

\- I couldn't find any real consensus on keeping immutable data structures in
Apollo. Since I favor to work with it, I kept it this way. However, in the
case of pagination and deep nested data structures, you would have to fallback
to a library to deal with it. Apollo adds their own immutable helper to the
whole tech stack which means to adapt yet another API... I wouldn't want to do
it and I think it's a bad decision to introduce yet another immutable helper.
That's why I picked the object spread operator.

\- I would hope that updateQuery goes away and one would be able to use
writeFragement in the update property to update the paginated data. If it's
possible, I would love to speak more about this topic with people more
knowledgable than me in Apollo :)

------
joshribakoff
I personally dislike some things about Apollo & prefer Redux+graphQL+RxJS
combo, and can't wait to see what happens w/ React Suspense

The problem with Apollo that I cannot get over is it couples data fetching to
components. The whole reason Redux is popular is it decouples UI actions from
data fetching. It decouples asynchronous logic from state mutations. Apollo
intentionally couples that logic.

With redux, I can dispatch an action anywhere in my app to trigger a data
fetch. That data fetch itself could be a graphQL query.

With apollo, I have to mount a component to trigger a data fetch. The
workaround to pre-fetch data is to render a "dummy" component, causing it to
pre-populate the cache.

Another issue, Apollo batching seems to be "all or nothing". Any components
mounting in the same event tick get batched into 1 query. This is a problem
when one query is in the critical UI path & is fast, but Apollo has batched it
together with a slow query that is not critical. Think about mounting an
<Article> with some <Comments> below it, but you don't want to wait on
rendering <Article> just because <Comments> is slow. Now you have your fast UI
components blocked from rendering because you're waiting on this batched
request.

With Redux I would get around the batching problem with redux-observable
middleware. I could write an epic that looks for actions, buffers these,
issues multiple graphQL queries (while giving me control over how to batch
them, if at all), and deal with responses in real-time as they arrive.

With Apollo v2, they totally ditched Redux. There is no escape hatches in
Apollo to deal with the problems that Redux solves. That being said, Apollo
cuts out tons of boilerplate & its a great library, so give it a try & decide
yourself. Personally I think co-locating data requirements with components is
a wonderful concept but the current implementation of graphQL clients is quite
stovepipe.

Also the landscape is about to shift again due to React suspense. You would
throw a promise in your render() method, and React will block rendering of the
component tree within a <Placeholder />, conceptually similar to error
boundaries. There is rumor of a Redux integration as well.

------
cbzehner
Definitely worth checking out.

If you're not yet onboard the React hype train I'd recommend the author's Road
To React course ([https://www.robinwieruch.de/the-road-to-learn-
react/](https://www.robinwieruch.de/the-road-to-learn-react/)), it's a good
introduction to React and modern JS and a leaping off point for more complex
stuff.

I worked through this in ~8 hours the weekend before a job interview and had
no trouble building and updating a simple React single page app as part of the
onsite.

------
pcmaffey
Now add a Node / Apollo server with Postgres backend and you'd have the
perfect example for IMO(!) the ideal modern starter stack.

