Repository navigation
feat: add the GraphQL extension spike (G0) - #1589
Merged
Merged
Conversation
This was referenced Oct 30, 2026
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved content-negotiation and response-handling defects can select explicitly rejected JSON, drop explicit null data, and throw uncaught runtime exceptions instead of diagnostic transport exceptions.
4 open issues
What changed in this PR
Adds the experimental GraphQL G0 extension, enabling GraphQL operations alongside REST resources through Restlet’s existing connectors. This establishes the module and adapter foundation for the later HTTP-binding phases.
Changes:
- Adds server and borrowed-client adapters using native graphql-java types, JSON transport, and transport exceptions.
- Registers the Maven and Java modules with graphql-java 26.1 and Jackson 3.
- Adds HTTP/2 round-trip, lifecycle, error-handling, and named-module tests, plus release notes.
| File | Description |
|---|---|
pom.xml |
Registers the extension and graphql-java version. |
org.restlet.ext.graphql/src/test/java/org/restlet/ext/graphql/GraphqlTestSchemas.java |
Supplies shared query and mutation schemas. |
org.restlet.ext.graphql/src/test/java/org/restlet/ext/graphql/GraphqlSharedPortTestCase.java |
Tests REST/GraphQL coexistence over HTTP/2 and lifecycle behavior. |
org.restlet.ext.graphql/src/test/java/org/restlet/ext/graphql/GraphqlModulePathTestCase.java |
Compiles and runs a named-module consumer. |
org.restlet.ext.graphql/src/test/java/org/restlet/ext/graphql/GraphqlHttpErrorsTestCase.java |
Tests request errors, negotiation, and transport failures. |
org.restlet.ext.graphql/src/main/java/org/restlet/ext/graphql/package-info.java |
Documents the experimental public adapters. |
org.restlet.ext.graphql/src/main/java/org/restlet/ext/graphql/internal/package-info.java |
Documents the internal package. |
org.restlet.ext.graphql/src/main/java/org/restlet/ext/graphql/internal/GraphqlMediaTypes.java |
Defines response media types and negotiation. |
org.restlet.ext.graphql/src/main/java/org/restlet/ext/graphql/internal/GraphqlJson.java |
Provides JSON conversion and bounded reads. |
org.restlet.ext.graphql/src/main/java/org/restlet/ext/graphql/GraphqlTransportException.java |
Exposes transport failure status and body excerpts. |
org.restlet.ext.graphql/src/main/java/org/restlet/ext/graphql/GraphqlServerAdapter.java |
Hosts GraphQL execution through a POST endpoint. |
org.restlet.ext.graphql/src/main/java/org/restlet/ext/graphql/GraphqlClientAdapter.java |
Sends operations through a borrowed Restlet client. |
org.restlet.ext.graphql/src/main/java/module-info.java |
Declares module dependencies and public exports. |
org.restlet.ext.graphql/pom.xml |
Defines extension dependencies. |
changes.md |
Records the experimental extension and dependency addition. |
Review effort: Balanced
jlouvel
force-pushed
the
feat/graphql-g0-spike
branch
from
November 1, 2026 14:23
c64f032 to
0fb3e9e
Compare
Add org.restlet.ext.graphql, hosting graphql-java 26.1 behind a Restlet and sending GraphQL operations through a borrowed Client: - GraphqlServerAdapter: POST with a JSON body, execution on the call's virtual thread, application/graphql-response+json or application/json responses, 400 for malformed requests, 405 for other methods. - GraphqlClientAdapter: constructor and setters frozen by start(), native ExecutionResult values, GraphqlTransportException with the status and a body excerpt when no GraphQL response is received. - graphql-java, java-dataloader and reactive-streams have no module descriptor. A test compiles a named consumer module and runs a round trip in a module layer using their automatic module names (com.graphqljava, org.dataloader, org.reactivestreams). - A query and a mutation round trip on one HTTP/2 port next to a REST resource. Refs #1582 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
Treat an entity without a stream as an empty response, report malformed results as transport exceptions, keep an explicit null data entry, and use the quality of the most specific matching Accept range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jlouvel
force-pushed
the
feat/graphql-g0-spike
branch
from
November 1, 2026 20:09
0fb3e9e to
4990292
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Closes #1582. Part of #1581.
Summary
Adds
org.restlet.ext.graphql, a new experimental extension that hosts graphql-java 26.1 behind aRestletand sends GraphQL operations through a borrowedorg.restlet.Client.graphql-javatypes (GraphQL,ExecutionResult,GraphQLError,Document) are the public model; the extension only implements the HTTP binding.POSTwith a JSON body; execution on the call's virtual thread (asynchronous fetchers are joined there);application/graphql-response+jsonwhen the client names it,application/jsonotherwise (wildcards and noAcceptselectapplication/json, per the draft's legacy rule);400with a GraphQL error body for malformed requests,405for other methods,406when neither type is acceptable.start(); nativeExecutionResultvalues;GraphqlTransportExceptionwith the status and a bounded body excerpt for connection failures and non-GraphQL responses (HTML502, empty401, invalid JSON). Response size is bounded (10 MiB).org.restlet,graphql-javaandjackson-databind3 directly (notorg.restlet.ext.jackson, to avoid its CSV, Smile, XML and YAML formats).Spike findings
graphql-java26.1,java-dataloader6.0.0 andreactive-streams1.0.3 have no module descriptor. Their automatic module names arecom.graphqljava,org.dataloaderandorg.reactivestreams.GraphqlModulePathTestCasecompiles a named consumer module withjavacand runs a full round trip in aModuleLayerbuilt from the real artifacts.CompletableFuturefetcher completes and is joined there.graphql-java's defaultSimpleDataFetcherExceptionHandlerputs the exception message in the error (Exception while fetching data (/failing) : …). The extension doesn't change errors; applications that must hide messages configure their ownDataFetcherExceptionHandler. The test pins this behavior.graphql-javareadsParserOptionsfrom theGraphQLContextof eachExecutionInput, so limits can be applied per execution without touching the process-wide defaults (used in G1).Validation
./mvnw -B verify -P default,test -pl org.restlet.ext.graphql: 13 tests, 0 failures; 89% instruction coverage (gate 80%); Spotless, SpotBugs (0 findings), Javadoc,-Werrorand dependency convergence pass.GraphqlSharedPortTestCase: a REST resource, a query and a mutation on one HTTP/2 (h2c) server connector; virtual threads; partial data with field errors; transport failure; lifecycle and borrowed-client ownership.GraphqlHttpErrorsTestCase: 405, 400 (no body, invalid JSON, batch array, missing or non-stringquery), negotiation and 406,operationName/variables/extensionsforwarding, start without aGraphQL, client transport errors and request errors as results.GraphqlModulePathTestCase: named-module consumer.Next
G1 (#1583) completes the server binding (GET, status codes per media type, limits, request context) on top of this branch.
🤖 Generated with Claude Code