Skip to content

feat: complete the GraphQL client HTTP binding (G2) - #1591

Open
jlouvel wants to merge 1 commit into
feat/graphql-g1-serverfrom
feat/graphql-g2-client
Open

jlouvel wants to merge 1 commit into
feat/graphql-g1-serverfrom
feat/graphql-g2-client

Conversation

@jlouvel

@jlouvel jlouvel commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Closes #1584. Part of #1581.

Stacked on #1590 (G1), itself on #1589 (G0). Merge those first.

Summary

Completes GraphqlClientAdapter.

GraphqlClientAdapter graphql = new GraphqlClientAdapter(getContext());
graphql.setClient(restletClient);                         // borrowed: auth, proxy, timeouts
graphql.setEndpoint("https://api.example.com/graphql");
graphql.setSchema(UnExecutableSchemaGenerator.makeUnExecutableSchema(new SchemaParser().parse(sdl)));
graphql.setRequestCustomizer(request -> request.getHeaders().add("Authorization", apiKey));
graphql.start();
ExecutionResult result = graphql.execute(document, "GetIssue", Map.of("id", id));
Aspect Behavior
Request POST, Accept: application/graphql-response+json, application/json;q=0.9; variables serialized as JSON values, never templated as text
Local validation With setSchema, documents (String or Document) are parsed with the adapter's ParserOptions and validated; invalid ones return an ExecutionResult with errors and no network call. The adapter never fetches a schema
Request errors A 2xx or 4xx response with a GraphQL body is an ExecutionResult (no data when execution didn't start)
Transport errors Connection failures, timeouts, responses above maxResponseBytes (10 MiB, checked on the declared size and while reading, never truncated) and non-GraphQL responses throw GraphqlTransportException with the status and a 1 KiB body excerpt
Authentication Through the borrowed Client, or the request customizer

The HTTP status of a request error is not exposed on the ExecutionResult; isDataPresent() tells request errors from execution results. A follow-up can expose it if callers need it.

Validation

./mvnw -B verify -P default,test -pl org.restlet.ext.graphql: 31 tests, 0 failures; 96.3% instruction coverage (gate 80%); Spotless, SpotBugs, Javadoc, -Werror and dependency convergence pass.

New GraphqlClientTestCase (6 tests), against GraphqlServerAdapter and against an independent server: the JDK HttpServer running graphql-java the legacy way (chunked application/json, 200 for validation errors, 422 with a GraphQL body on another path):

  • Text with {{…}}, quotes, {key=value}, backslashes, newlines and non-ASCII characters round trips unchanged in nested input objects (the escaping failures seen when GraphQL is templated as opaque JSON).
  • Legacy validation errors and 4xx GraphQL bodies are results.
  • Local validation of string and parsed documents with no network call (counted on the peer).
  • Response limit with declared and chunked bodies.
  • Request customizer; frozen configuration.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The Document overload bypasses configured parser limits, allowing operations rejected by the string overload to reach the server instead of returning local errors.

1 open issue
What changed in this PR

Completes the GraphQL client HTTP binding over a borrowed Restlet client, adding local validation and configurable response limits.

Changes:

  • Adds optional schema validation, parser options, response-size limits, and request customization.
  • Adds interoperability tests for JSON variables, error responses, validation, limits, and frozen configuration.
  • Updates the changelog with the client capabilities.
File Description
org.restlet.ext.graphql/​src/​test/​java/​org/​restlet/​ext/​graphql/​GraphqlTestSchemas.java Adds input-echo and header fields for client tests.
org.restlet.ext.graphql/​src/​test/​java/​org/​restlet/​ext/​graphql/​GraphqlClientTestCase.java Tests client behavior against Restlet and an independent HTTP server.
org.restlet.ext.graphql/​src/​main/​java/​org/​restlet/​ext/​graphql/​GraphqlClientAdapter.java Adds validation, configurable limits, and request customization.
changes.md Documents the expanded GraphQL client capabilities.

Review effort: Balanced

Comment on lines +294 to +297
ExecutionResult invalid = validate(document);
return invalid != null
? invalid
: send(AstPrinter.printAst(document), operationName, variables);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining: the parser options bound the cost of parsing untrusted text, and a Document overload receives an AST the caller already built, so there is nothing left to protect locally (the string overload doesn't parse either without a schema). Reprinting and reparsing every Document just to apply token limits would add cost for no safety gain; the server still applies its own limits.

- setSchema(GraphQLSchema): documents are parsed and validated locally,
  and invalid ones are returned as an ExecutionResult with errors
  without a network call. The adapter never fetches a schema.
- setParserOptions for local parsing; setMaxResponseBytes (10 MiB by
  default) checked on the declared size and while reading, never
  truncated; setRequestCustomizer for API key headers.
- Variables are serialized as JSON values: text with braces, quotes,
  backslashes and newlines round trips unchanged.
- Tested against GraphqlServerAdapter and against an independent server
  (the JDK HttpServer running graphql-java the legacy way, with chunked
  application/json responses and a 422 with a GraphQL body).

Refs #1584

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
@jlouvel
jlouvel force-pushed the feat/graphql-g2-client branch from 1690ade to 4eaa979 Compare October 31, 2026 06:07
@sonarqubecloud

Copy link
Copy Markdown

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.

2 participants