
Show HN: Quiver – GraphQL on Steroids - syrusakbary
https://medium.com/@syrusakbary/quiver-graphql-on-steroids-13612ea1ea77
======
ianstormtaylor
Quiver looks interesting, congrats on launching! It seems like it will be very
useful for internal GraphQL APIs.

It does bring up something that I think the GraphQL community hasn't really
addressed well yet though... Part of the way Quiver works is that it only
allows pre-defined queries which can then be compiled ahead of time.

> Only allow certain queries from a document store.

This is becoming a common response for how to make GraphQL performant and
"secure". [1]

But this solution only works for internal APIs. If you're trying to expose a
public GraphQL API it isn't viable.

Not only that, but to sync these "persisted" queries from the client to the
server, lots of the persisted query tools require you to hard-code GraphQL
queries as `.graphql` files in your repository... effectively re-inventing
hard-coded REST responses. Except with an extra build process between the
client and the server for each new deploy. You no longer really have each
component requesting exactly what it needs.

The more research I do into GraphQL, the more it seems like the promise of
"query anything" that libraries are selling is often discarded when you get to
actual implementation. And you end up with a situation that is much more
similar to REST/HTTP than originally intended.

[1]: [https://dev-blog.apollodata.com/persisted-graphql-queries-
wi...](https://dev-blog.apollodata.com/persisted-graphql-queries-with-apollo-
client-119fd7e6bba5)

~~~
djmashko2
Open source lead at Apollo here:

The most important thing about the persisted queries approach highlighted in
that article, compared to traditional REST architecture, is that the queries
live in your _client_ codebase. So the frontend developers write the shape of
the data, rather than backend folks hardcoding it in like with endpoints.

I would say that at the current moment only a small minority of GraphQL users
(based on our experience) are using persisted queries, and running in
production without that is just fine with good performance and security. A
simple approach like query timeouts, or discarding queries based on
complexity, goes a long way here.

~~~
ianstormtaylor
Thanks for the response!

I agree, having queries live in the client is a great goal for DX on the
frontend. The ideal being to have them co-located right with the components
that need the data. But the issue is that these kinds of solutions are often
presented without discussing their tradeoffs. From the article:

> Because persisted queries are static by definition, they also give you the
> possibility of optimizing execution on the server for specific queries, for
> example by hand-crafting a highly efficient database query.

Well, that's a bit harder when the client controls the queries and they're
automatically "recompiled" on each new deploy, because now you're optimizing a
moving target that could change dramatically with little notice. It's not
really a benefit, since it's such a fragile situation to be relying on in the
first place.

Persisted queries also kind of make co-location of queries with components a
non-starter. Maybe Apollo doesn't want to allow co-located queries, which
could be an okay decision, but isn't really discussed much as a tradeoff.

And then it doesn't solve the larger issue that these solutions don't work for
public-facing APIs. So you end up having to solve the same issues (eg.
bandwidth, security, caching) again in an entirely new way.

I think it's something the community will need to address if public-facing
GraphQL APIs are going to flourish.

~~~
underwater
Relay Modern allows co-located queries with components.

I don’t understand your concerns about performance or security. GraphQL should
only expose the fields you can fetch in a fast and safe way. Optimise the
field lookups; not the whole query execution.

A deeply nested GraphQL request is no worse than a series of REST fetches.

------
KenanSulayman
Juniper - GraphQL library (+ Server if you want it to) written in Rust:
[https://github.com/graphql-rust/juniper](https://github.com/graphql-
rust/juniper)

We’re using Juniper in production as a central API for other internal
services.

The performance of literally any other GraphQL server is just hilariously slow
compared to it.

We previously used Node GraphQL and were happy with it, but at some point we
needed more raw speed.

(edit: just to make it clear -- I'm not affiliated with this project)

~~~
e12e
This will come off as a bit snarky, but I'm really just trying to be direct.
It's always great when people share their hard work!

> The performance of literally any other GraphQL server is just hilariously
> slow compared to it.

Is the same kind of fast as in getting the data from the sql server takes half
a second, but x then renders the response in 20 ms not a slow 80 ms (520 vs
580 ms response time to the client)?

I mean, I unless your data is in an in-memory in-process database, it comes
from the network to the graphql server, which acts as a proxy for the client?

Which makes a claim of being a lot faster than eg nodejs interesting - but
also somewhat surprising.

~~~
KenanSulayman
There's a lot to this. First off, I was talking about internal services -- the
"this is essentially a very expressive interface to a database" kind of
GraphQL API. There's no 500ms network overhead. In fact, there's not even 20ms
network overhead. Those 50ms are pretty substantial in this setup.

For most GraphQL API requirements in terms of performance there's no real
value in using Rust if you're not already very proficient in it.

That said, 520ms is extremely pessimistic for most GraphQL servers.

The API to a project I'm running is built using the Node / Apollo GraphQL
server and its response times are well under 90ms; that's with a CDN in
between: [https://api.psychonautwiki.org](https://api.psychonautwiki.org).
[server in Germany; US mileage may vary]

(btw -- _I 'm not affiliated with Juniper_)

~~~
e12e
Thank you for clarifying.

As for the 500ms I wasn't thinking only network overhead, but also things like
complex sql queries with lots of joins etc. And maybe on top of that going
through a json-rest/soap endpoint:

Client > graphql server > rest endpoint 1..3 > [sql server, document db, key-
value store]

Where the graphql server takes a query, fetches and merges resources, and
sends the result back to the client. (and as you mention, maybe rest and rest
are external services)

If it's just:

Client > graphql > documentdb

(since your link mentions wiki...) - I'm not sure I see that graphql is a
great benefit (but I'm perfectly open to that being wrong; as I said, I've
only just begun looking at graphql).

~~~
KenanSulayman
You're much correct about the performance implications of complex external
queries. 500ms to 600ms is very realistic in that case. But I assume that you
can always cache specific parts of the external requests, although the
efficiency of that is very dependent on the homogeneity of your requests.

And you're very right that GraphQL isn't very smart for a wiki (besides being
a fancy replacement for REST).

PsychonautWiki is documenting the effects (and dosage, durations, ...) of
hallucinogenic substances; GraphQL allows people to easily query for
substances with similar effects, or substances from the same class, .., all in
a single request. Also you get type checking and field selection for free.

------
hn_throwaway_99
Your second bullet point, "Only allow certain queries from a document store",
seems to be a major, major limitation, and directly contrary to one of the
principal design goals of GraphQL.

~~~
syrusakbary
Companies like Facebook limit the documents that can be queried against their
GraphQL API this way.

There are some major benefits of this: \- improving the speed of the HTTP
request (it always be faster to just send a documentId rather than a big query
sting from the client side) \- Control what is queried against your API (so
there are no "Facebook" clones with some extra views)

At the end, with enough tooling you can make the frontend projects upload
their documents queries automatically as their developers work on it. So the
tradeoffs for GraphQL APIs focused on internal products are not as bad.

~~~
underwater
I don’t think Facebook is limiting the queries that can be run. Persisted
queries are an optional optimisation on top of dynamic queries.

------
oceanghost
Those of us who are on steroids, do not appreciate being compared to GraphQL.
:-)

------
biznickman
Sooo Quiver is just caching?

~~~
syrusakbary
Hi Nick,

Quiver will compile the GraphQL query code to runtime code. Is a similar
approach of what v8 does when executing JS (it compiles it to assembly code),
or what modern template engines do to speed up their rendering.

So basically, it will transform the GraphQL query into a pure function that
can be executed without the overhead of having the GraphQL engine doing the
calculations at runtime.

~~~
Finnucane
And this is worth $200/month?

~~~
CGamesPlay
If it allows you to run 5 fewer servers to handle your traffic, then very
probably, yes.

------
city41
Just FYI: Chrome tells me graphene.tools SSL cert is not valid.

------
angryasian
why wasn't apollo server included in the benchmarks ?

~~~
djmashko2
Open source lead at Apollo here.

Syrus is correct that it will have about the same performance as Node in these
particular benchmarks.

We are working on performance improvements for Apollo Server 2.0, but they are
targeted at a totally different use case. Our experience working with hundreds
of companies using GraphQL in production has indicated that the CPU execution
time of the query is almost never the bottleneck when it comes to GraphQL.

The real thing you want to watch out for is the time it takes to call
underlying APIs and databases, which will absolutely dwarf the actual time
spent in the CPU. In this case, Node's non-blocking architecture helps a ton,
and taking any action that prevents repeated calls (like basic caching) is
critical.

In AS 2, we're going to introduce some features that make caching underlying
data calls even easier, which we think is going to have the biggest impact on
people's response time with GraphQL.

~~~
ianstormtaylor
+1 to this. These kinds of benchmarks of the actual execution of a server are
almost never useful for actual production loads—it's always going to be the
database or external services.

It's the same kind of thing as Express.js competitors showing that their
routing logic handles 50k requests per second instead of Express's 25k, but
only for "simple" use cases—AKA ones that don't involve a database. You should
almost never be evaluating a server on these parameters.

