Skip to content

feat(graphql): document option and query params in the url - #154

Merged
prc5 merged 6 commits into
mainfrom
feat/graphql-document-and-query-params
Nov 3, 2026
Merged

prc5 merged 6 commits into
mainfrom
feat/graphql-document-and-query-params

Conversation

@prc5

@prc5 prc5 commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Closes #153

Summary

A GraphQL request can now have its own URL path, and setQueryParams() reaches the URL.

const getUser = client.createRequest<{ response: UserResponse; payload: { id: number } }>()({
  endpoint: "/User", // URL path, appended to client.url
  document: USER_QUERY, // string | DocumentNode, sent as `query`
});

getUser.setQueryParams({ source: "app", build: "1.2.3" }).send({ payload: { id: 1 } });
// POST {client.url}/User?source=app&build=1.2.3
// body: { query, variables: { id: 1 } }
  • POST: query params are appended to the URL, query and variables stay in the body.
  • GET: query params are merged with query and variables, which win on collision (also for forms like query[]=x).
  • Mapper: query params go through unstable_queryParamsMapper, which may return a string or an object.
  • Without document: endpoint is still the document and the URL is still client.url.

Changes by package

  • core: a new trailing Adapter generic lets an adapter declare extra createRequest fields, so document is a type error on other adapters and survives mapper setters. The devtools endpoint getter also receives the request options.
  • graphql: URL building, query params, and key mappers.
  • testing: createGraphqlMockingServer handles document requests and matches the full path. It would otherwise have thrown on them.
  • hyper-flow: passes the request options to the devtools endpoint getter.
  • docs: URL path and query params sections in the GraphQL overview.

Decisions to review

  1. Keys include the path. The issue asks for the operation name from document. Keys also contain the path (POST_GetUser/User--), because otherwise /v1/User and /v2/User would share cached data. Keys of requests without document are unchanged.
  2. Query params also apply without document. The issue says "nothing changes" there, but also lists ignored query params as a limitation. Those requests now go to client.url?source=app, which only affects code already calling setQueryParams().
  3. Variables are not inferred from document. ExtractGqlRouteParams is not connected to createRequest today, and a gql document can't be read at the type level. send({ payload }) still needs the payload generic, which the example in the issue leaves out. String documents can use payload: ExtractGqlRouteParams<typeof USER_QUERY>.
  4. Wider default query params type. It is now QueryParamsType | string | undefined, so setQueryParams({...}) compiles without declaring queryParams.

Known limitations

  • setQueryParamsMapperConfig replaces the defaults, including encoding, so a partial config sends unencoded values. The docs show spreading stringifyDefaultOptions.
  • The devtools UI was not opened. The operation name display is covered by unit tests of the getter only.

Test plan

Same steps as CI, run from the repository root with exit codes checked:

  • pnpm build
  • pnpm lint (run per package, 12 of 12 with exit code 0)
  • pnpm typecheck
  • pnpm test (firebase and firebase-admin are excluded by the script)
  • graphql: 118 tests, 10 runs in a row before the last hyper-flow fix, including E2E against a real HTTP server that checks the path and query string
  • Type tests with expectTypeOf and @ts-expect-error

🤖 Generated with Claude Code

prc5 and others added 5 commits November 3, 2026 12:56
Adapters can declare additional createRequest fields with a new generic,
so they are type checked only on clients using that adapter. The devtools
endpoint getter also receives the request options to read those fields.

Refs #153

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the document option the endpoint becomes a URL path appended to
client.url. Query params go through the adapter mapper and are appended to
the URL, on GET query and variables win on collision. Keys contain the
operation name from the document and the path. Without the document option
the endpoint still holds the document and the URL is client.url.

Closes #153

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #153

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #153

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #153

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@prc5
prc5 requested a review from GerasNyx as a code owner November 3, 2026 11:57
getEndpointAndMethod now takes the request and the client. The extra
parameter for the request options broke the max-params lint rule in CI.

Refs #153

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@prc5
prc5 merged commit ff099cf into main Nov 3, 2026
4 checks passed
@prc5
prc5 deleted the feat/graphql-document-and-query-params branch November 3, 2026 14:18
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 9.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow a request to have both a URL path (endpoint) and a GraphQL document

1 participant