Skip to content

fix(graphql): ship kotlinx serializers for the GraphQL wire types - #55

Merged
Ziedelth merged 3 commits into
masterfrom
fix/graphql-kotlinx-serialization
Oct 19, 2026
Merged

Ziedelth merged 3 commits into
masterfrom
fix/graphql-kotlinx-serialization

Conversation

@Ziedelth

@Ziedelth Ziedelth commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #47, found and verified with real HTTP integration tests.

fix(graphql): kotlinx serializers for the GraphQL wire types

Root cause: GraphQLServerRequest and GraphQLResponse (graphql-kotlin-server 10.2.2) are annotated for Jackson / FastJson only - no kotlinx serializer exists. A kotlinx ContentNegotiation therefore can neither parse a GraphQL body nor write its response: Cannot transform this request's content to GraphQLServerRequest whatever the Content-Type/Accept.

  • graphQLSerializersModule carries both directions (single request object, batch array; data/errors/extensions response) - consumers register it with configureDefaultModules(graphQLSerializersModule);
  • configureContentNegotiation accepts extra SerializersModules merged into the JSON converter;
  • argument resolution moved inside the guarded block: a malformed parameter answers its 400 MessageDto instead of escaping as a 500.

fix(ktor): the real response size in the request logs

The log read Content-Length from the response headers, which the engine computes while writing and often never exposes there: every request printed NaN. ResponseSizeRecorder measures the outgoing content at send time (ResponseBodyReadyForSend) and stores it in a call attribute the request log formats - whatever the engine and the negotiated format.

style

Top-level extensions at the top of the file, KDoc on all of them (private included), and method references over lambdas in the GraphQL serializers.

Verified end to end (core api/src/integrationTest)

Real embedded server, real HTTP requests:

  • POST /graphql with a query body -> 200 with data (died before);
  • GET /animes in json, protobuf and cbor -> 200 in all three;
  • response size logged for json, protobuf and cbor (asserted on the captured logs, no NaN);
  • GET /animes/not-a-uuid -> 400.

Version bumped to 0.0.23-SNAPSHOT (core pinned on it).

GraphQLServerRequest and GraphQLResponse are Jackson-only types: a kotlinx ContentNegotiation can
neither read a request body nor write a response, so every GraphQL call died with
'Cannot transform this request's content' regardless of the headers. graphQLSerializersModule now
carries both directions and consumers register it in their JSON converter.

Also: argument resolution moved inside the guarded block of the request handler, so a malformed
parameter is refused with its 400 instead of escaping as a 500.
The log read Content-Length from the response headers, which the engine computes while writing and
often never exposes there: every request printed 'NaN'. ResponseSizeRecorder now measures the
outgoing content at send time (hook ResponseBodyReadyForSend) and stores the size in a call
attribute that the request log formats - whatever the engine and the negotiated format.

Verified on real HTTP integration tests: End - AnimeController.findById (27.56 ms; 66 B).
…L serializers

The private extensions of GraphQLServerRequestSerializer now sit at the top of the file and all
carry their KDoc, and the list mappings use method references (GraphQLRequest::toElement,
JsonElement::toValue, Any?::toElementValue) instead of lambdas.
@Ziedelth
Ziedelth merged commit a6da9aa into master Oct 19, 2026
2 checks passed
@Ziedelth
Ziedelth deleted the fix/graphql-kotlinx-serialization branch October 19, 2026 07:22
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