Agent Wranglers

API-86Optional

Allow only known queries from your own apps

When only your own apps call a GraphQL API, register each query at build time. The server runs only registered queries, sent by their hash.

How to do it

Registered queries, also called trusted documents, turn an open query language into a fixed list. A stranger then cannot send a costly or probing query at all. The client sends a hash, which also shortens requests and lets GET answers be cached. Keep the open endpoint for public or partner APIs, with the limits from lock down GraphQL endpoints. Old app versions still send old hashes, so keep each registered query as long as keep old app versions working against the API asks.

Examples

JavaScript example

const trusted = new Map(Object.entries(JSON.parse(readFileSync('persisted-queries.json', 'utf8'))));

app.post('/graphql', express.json(), (req, res, next) => {
  const query = trusted.get(req.body?.extensions?.persistedQuery?.sha256Hash);
  if (!query) return res.status(400).json({ errors: [{ message: 'Unknown query', extensions: { code: 'PERSISTED_QUERY_NOT_FOUND' } }] });
  req.body.query = query;
  next();
});

Python example

TRUSTED = json.loads(Path("persisted-queries.json").read_text())

def resolve_query(body: dict) -> str:
    query_hash = body.get("extensions", {}).get("persistedQuery", {}).get("sha256Hash")
    if query_hash not in TRUSTED:
        raise UnknownQuery(query_hash)
    return TRUSTED[query_hash]

How to check

Send a valid query that is not on the list to production. It is refused. Every query in the client's build output has a hash in the server's list.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/api-design/graphql-and-grpc/graphql-trusted-documents">Agent Wranglers API design playbook</a>. In code you write, add a comment next to it with the same link.