Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persisted queries #196

Open
Daniel15 opened this issue Feb 20, 2019 · 8 comments

Comments

Projects
None yet
2 participants
@Daniel15
Copy link

commented Feb 20, 2019

Relay and Apollo support a concept called "persisted queries" whereby the GraphQL queries are persisted on the server side, and the client only needs to send an identifier (eg. a hash) to execute it. This avoids having to re-upload and re-parse the query every time it's executed, and the server can store the query in some intermediate form (such as a serialized AST) to improve performance.

Does urql support sending query IDs rather than the entire query? How would I integrate persisted queries into urql? I guess it'd need a Babel transform of some sort?

Reference: https://facebook.github.io/relay/docs/en/persisted-queries.html

Even better would be support for Apollo's "automatic persisted queries" (see https://blog.apollographql.com/automatic-persisted-queries-and-cdn-caching-with-apollo-server-2-0-bf42b3a313de)

@kitten

This comment has been minimized.

Copy link
Member

commented Feb 20, 2019

It does not, currently, but this can probably be achieved by writing an alternative fetchExchange. :) one of the ideas of urql is that it's super customisable. We can't provide all features out of the box but if anyone is willing to create a package for persisted queries let us know and we'll help out 👌

@Daniel15

This comment has been minimized.

Copy link
Author

commented Jun 3, 2019

So I've been thinking about this a bit... It seems like Apollo's "automatic persisted queries" would be a good relatively simple implementation. The protocol is documented here: https://github.com/apollographql/apollo-link-persisted-queries#protocol. Basically, you first try the query by just sending a SHA256 hash of the query. If the server already has the query text cached, it runs the query like normal. Otherwise, it returns a PersistedQueryNotFound error, at which point you need to send the full query text.

At a high level, I think you're right and this could use a modified version of the fetch exchange that first sends the query with just the hash, and if that fails, sends the entire query.

It seems like a lot of the existing fetch exchange (eg. the AbortController handling, most of the fetchOptions, etc) would be reusable. Should I pull the reusable stuff out into a separate module that both the current fetch exchange and this new hypothetical "persisted query fetch exchange" use? Or should I instead make the existing fetch exchange more pluggable, and have the new "persisted query fetch exchange" reuse the core fetch exchange?

@Daniel15

This comment has been minimized.

Copy link
Author

commented Jun 5, 2019

I'm working on this 😄 Do you think it'd be okay to live in this repo (and published as a separate package), or would you rather it be in a totally different repo?

@kitten

This comment has been minimized.

Copy link
Member

commented Jun 5, 2019

@Daniel15 Awesome! I think for now it'd be great if it could live in a separate repository, but let me know if you need any help setting sth up or making that work 👍 (You can also DM me on Twitter @_philpl)

Ultimately we don't want all custom exchanges to live in the main repository or package; maybe at some point we'll convert to a mono repo, but for now this might be the better way to proceed.

You could also implement this as an exchange that sits in front of fetch potentially? But whatever you prefer 😅 I'm not sure which one is easier to write right now

It also seems like any hash might work; they do specify that SHA256 is their default but the urql exchange could default to a non-cryptographic hash which we already generate in our exchange pipeline

@Daniel15

This comment has been minimized.

Copy link
Author

commented Jun 7, 2019

So I did get it working 😃

I just need to clean up the code a bit, as it's a bit messy at the moment. I'll post it to a new repo soon 😄

It also seems like any hash might work

You'd think that based on the docs, but actually if you use Apollo Server and try to persist a query, and send a hash that doesn't match the SHA256 of the query, it throws an error:

provided sha does not match query

Seems like it's hardcoded to use SHA256:

https://github.com/apollographql/apollo-server/blob/2d1544d049429f979cfcb28c9b83589e23873885/packages/apollo-server-core/src/requestPipeline.ts#L167-L172

https://github.com/apollographql/apollo-server/blob/2d1544d049429f979cfcb28c9b83589e23873885/packages/apollo-server-core/src/requestPipeline.ts#L68-L72

I imagine other implementations are similar (I'll have to see if there's a PHP implementation, as I'll be using this with a PHP server).

The Web Crypto API supports SHA256, so at least I don't need to load a JS library for SHA256 (in modern browsers at least).

@kitten

This comment has been minimized.

Copy link
Member

commented Jun 7, 2019

@Daniel15 Awesome! It'd be pretty cool to have an urql-exchange-persisted-queries or something! Excited for this issue to make some progress 🎉

It's a bit surprising given that their docs were a little unclear on this. I assumed it would accept any hash and associate it with a query on a cache-miss. Oh well

@Daniel15

This comment has been minimized.

Copy link
Author

commented Jun 9, 2019

I need to add a few more unit tests, but I published an initial version here: https://github.com/Daniel15/urql-persisted-queries. Let me know if you have any feedback :)

@Daniel15 Daniel15 closed this Jun 9, 2019

@Daniel15

This comment has been minimized.

Copy link
Author

commented Jun 9, 2019

@kitten - Actually is there somewhere in the docs I should link it from? Is there an index for "custom exchanges" at the moment?

@Daniel15 Daniel15 reopened this Jun 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.