Skip to content

Support Apollo's automatic persisted queries #1972

@vojtapol

Description

@vojtapol

This powerful feature is described here:
https://www.apollographql.com/docs/apollo-server/performance/apq/

There is very little that needs to be done by graphql-java to support this. The PreparsedDocumentProvider currently is meant to use the whole query as the cache key for the preparsed document. The cache could however also use the persisted query hash as a key. The only problem is that there is currently no good field on the ExecutionInput to store the hash.

I propose that hash field is added to ExecutionInput and that query is allowed to be null if hash is not-null.

Workaround

I have implemented a workaround using the the context object which works well but would prefer official support:

  1. Executing query:
context.hash = queryHash;
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
    .query(ofNullable(query).orElse("PERSISTED")) // query is not allowed to be null, so placeholder is needed
    .context(context)
    .build();
  1. PreparsedDocumentProvider::get:
public PreparsedDocumentEntry get(
    ExecutionInput executionInput,
    Function<ExecutionInput, PreparsedDocumentEntry> computeFunction
) {
    GraphQLContext context = (GraphQLContext) executionInput.getContext();
    String queryHash = context.hash; // hash stored in context, but it would be better if it could be on ExecutionInput

    if (queryHash != null) {
        return cache.get(queryHash, unused -> {
            // cache miss 
            if (executionInput.getQuery().equals("PERSISTED")) {
                // we must request the full query from the clientt
                throw new GraphQLPersistedQueryNotFoundException();
            }
            // we can now parse the query and store it as a value for the hash
            return computeFunction.apply(executionInput);
        });
    }

    // for clients that do not support automatic persisted queries
    return cache.get(executionInput.getQuery(), unused -> computeFunction.apply(executionInput));
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions