Skip to content

feat(g14a): GraphQL query matching, validated against the GraphQL extension#51

Merged
omercelikdev merged 1 commit into
mainfrom
feat/g14a-graphql
Jul 4, 2026
Merged

feat(g14a): GraphQL query matching, validated against the GraphQL extension#51
omercelikdev merged 1 commit into
mainfrom
feat/g14a-graphql

Conversation

@omercelikdev

Copy link
Copy Markdown
Owner

G14a — GraphQL query matching

The first GraphQL slice. Unlike gRPC, GraphQL needs no new transport — a GraphQL request is an ordinary POST /graphql with a {"query": …} body. So GraphQL is a request matcher that understands query equivalence; the whole serving path is unchanged.

Normalization — matches the reference exactly

The community WireMock GraphQL extension parses both queries, runs graphql-java's AstSorter, then compares with AstComparator — so equal queries match regardless of whitespace AND field/argument order. GraphqlQueryMatcher reproduces this with GraphQL-Parser: parse → recursively sort selections + arguments bottom-up (by printed form) → print canonically → string-compare. A syntax error on either side is a no-match.

Learned behavior: field/argument order is normalized, not just whitespace — confirmed on the oracle ({ hero { id name } } matches expected { hero { name id } }). Whitespace-only normalization would diverge; the AST sort is required.

Wiring

The adapter recognizes the graphql-body-matcher customMatcher and builds a GraphqlQueryMatcher(parameters.query). (The param key query was discovered from the extension source — the natural guesses expectedQuery/requestJson are not it.) Any other customMatcher name still resolves via the G10 registry.

Validation

G14aGraphqlTests.QueryMatching_AgreesWithTheOracle: the community extension (io.github.nilwurtz, loaded via --extensions) is the oracle. The same stub is loaded into both sides and five query variants are POSTed to /graphqlexact, reformatted (whitespace), reordered fields, a different query, and a syntactically invalid one. The match/no-match decision agrees on every variant.

Full suite: 102 differential, 9 application, 0 warnings.

Explicitly deferred (tracked)

variables + operationName matching (the extension also compares those); GraphQL response templating.

New dep: GraphQL-Parser 9.5.1 (graphql-dotnet's parser, MIT), used only inside Mockifyr.Matching. The extension jar is fetched from Maven Central at test time (cached), not committed.

Docs: docs/parity/g14-graphql.md (new), docs/roadmap.md (G14a ticked).

🤖 Generated with Claude Code

…ension

GraphQL parity by matcher, not transport: a GraphQL request is an ordinary
POST /graphql with a {"query": ...} body, so the serving path is unchanged —
GraphQL adds a request matcher that understands query equivalence.

GraphqlQueryMatcher normalizes exactly as the reference extension does: parse
both queries (GraphQL-Parser), sort the AST (recursively order selections and
arguments bottom-up by printed form — the community extension uses
graphql-java's AstSorter), print canonically, and string-compare. So equal
queries match regardless of whitespace AND field/argument order; a syntax
error on either side is a no-match. The adapter recognizes the
graphql-body-matcher customMatcher (parameters.query = the expected query;
the key was discovered from the extension source); any other customMatcher
name still resolves via the G10 registry.

Validated against the community WireMock GraphQL extension oracle
(io.github.nilwurtz, loaded via --extensions): the same stub in both sides,
five query variants POSTed to /graphql (exact, reformatted, reordered
fields, different, invalid) — the match/no-match decision agrees on every
one. Suite green (102 differential, 9 application).

Deferred (tracked): variables + operationName matching; GraphQL response
templating.

Refs: G14a

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@omercelikdev omercelikdev merged commit 3d7a1a2 into main Jul 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant