Using Persisted Queries
Persisted queries are an advanced GraphQL feature that allow clients to pre-register queries with the server. In a typical workflow, the client will send the query to the server as part of a build process and the server will send back an id. When the client wants to run the query, it sends the id instead of the full query string.
Developers use persisted queries because they reduce the amount of bandwidth sent from the client to the server and they improve security by locking down the queries that can be sent to the server.
Persisted queries with OneGraph
OneGraph persisted queries are created with a mutation
mutation PersistQuery($query: String!, $appId: String!) {
onegraph {
createPersistedQuery(input: {query: $query, appId: $appId}) {
persistedQuery {
id
}
}
}
}
The id of the persisted query is sent in the JSON body as doc_id
in place of the query
field.
curl https://serve.onegraph.com/graphql?app_id=$APP_ID \
-X POST \
-H 'Content-Type: application/json' \
--data '{"doc_id": "42463012-2cc1-46b4-90f5-f1f042c1be1c"}
fetch('https://serve.onegraph.com/graphql?app_id=' + APP_ID, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
doc_id: '42463012-2cc1-46b4-90f5-f1f042c1be1c',
}),
});
You can create persisted queries from the "Persisted queries" tab of the dashboard.
Persisted queries as mini serverless functions
OneGraph's persisted queries offer three features that make them well-suited for use as a replacement for custom API endpoints or serverless functions.
They support
- Embedded auth
- Full control over variables
- Caching
Embedded Auth
The accessToken
argument on the persistQuery
mutation allows you to associate an auth token (which you can generate on the Server-Side Auth
tab of the dashboard) with your persisted query. Use this to grant your users fine-grained access to read and write data to your third-party accounts.
A few examples of things you could allow your users to do are:
- Build a blog on top of GitHub issues
- Create a ticket on Zendesk
- Subscribe to a mailing list on Mailchimp
- Download a file from your Dropbox account
- Add an issue to your GitHub repo
- Create an entry in Airtable or a Google Sheet
- Autofill a form with data from Clearbit
- List upcoming meetups on your blog
Full control of variables
The freeVariables
argument on the persistQuery
mutation allows you to specify a list of variables that the caller of the query is allowed to specify. This allows you to control how dynamic your queries are.
Caching
The cacheStrategy
argument on the persistQuery
mutation allows you to specify a ttl for the query. OneGraph will cache the result of the query for the specified number of seconds to avoid overwhelming the upstream API.
Fallback on error
Set the fallbackOnError
argument to true to make your query more robust against transitory errors or rate limits from the underlying APIs.
If set to true, and there was a successful execution of the query in the last 30 days, then the last successful result will be returned if we encounter any error when executing the query. If we do not have a previous successful result, then the response with the error will be returned.
Note that the fallback result will be returned even in the case of partial success (i.e. the errors
field has at least one error, but the data
field is not null
).
The query must provide a cache strategy in order to use fallbackOnError
.
If the fallback response is used, the extensions
field will be populated with a few fields to inform you that the fallback was used, when it was last stored, and what the error was.
Example fallback response:
{
"data": {
"npm": {
"package": {
"name": "relay",
"id": "relay",
"distTags": {
"latest": {
"versionString": "0.8.0-1"
}
}
}
}
},
"extensions": {
"persistedQueryFallback": true,
"lastModified": "2021-06-15T02:29:28-00:00",
"errors": [
{
"message": "Whoops!",
"path": [
"npm",
"package"
]
}
]
}
}
Persisting queries with an automated workflow
You must be logged in to OneGraph to create a persisted query for your app. If you want to persist queries in an automated workflow, OneGraph allows you to create a token that can be used to persist queries on your behalf. The holder of the token can only use it to run the persistQuery mutation.
Javascript example
The following example will create a persisted query that gets information about a package on npm. You can run it in the browser console to test. Be sure to replace REPLACE_WITH_TOKEN
with an API token that you create on the "Persisted queries" tab of the dashboard.
// Get an API token from the "Persisted queries" tab of the dashboard
const ONE_GRAPH_PERSIST_QUERY_TOKEN = REPLACE_WITH_TOKEN;
// Change this to your app's ID
const ONE_GRAPH_APP_ID = APP_ID;
const persistQueryMutation = `
mutation PersistQuery(
# variables that the caller of the query can provide
$freeVariables: [String!]
# default variables for the query
$fixedVariables: JSON
# You app' id
$appId: String!
# Optional access token ifK you want the caller of the query to use your auth
$accessToken: String
$query: String!
) {
oneGraph {
createPersistedQuery(
input: {
query: $query
accessToken: $accessToken
appId: $appId
freeVariables: $freeVariables
}
) {
persistedQuery {
id
}
}
}
}
`;
const queryToPersist = `
query NpmPackageQuery($package: String!) {
npm {
package(name: $package) {
homepage
description
distTags {
latest {
version {
version
}
}
}
}
}
}
`;
fetch(`https://serve.onegraph.com/graphql?app_id=${ONE_GRAPH_APP_ID}`, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + ONE_GRAPH_PERSIST_QUERY_TOKEN,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: persistQueryMutation,
variables: {
query: queryToPersist,
// Allows the client to provide the "package" variable
freeVariables: ['package'],
appId: ONE_GRAPH_APP_ID,
accessToken: null,
fixedVariables: null,
},
}),
})
.then((resp) =>
resp.json().then((json) => {
const queryId = json.data.oneGraph.createPersistedQuery.persistedQuery.id;
console.log('QueryId:', queryId);
}),
)
.catch((e) => console.error('Error saving query', e));