Skip to content

Declare that GraphQL response data can be optional and skippable - #611

Merged
xperiandri merged 2 commits into
devfrom
graphql-response-data-skippable
Sep 18, 2026
Merged

xperiandri merged 2 commits into
devfrom
graphql-response-data-skippable

Conversation

@xperiandri

@xperiandri xperiandri commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Changes GQLResponse.Data to Skippable<Output voption> and propagates that contract through the minimum required execution and test surfaces.

Review scope

Please review only response-data presence/nullability semantics. Generic streaming fixes, middleware changes, WebSocket lifecycle, and active-pattern changes are intentionally excluded into separate PRs.

Generic streaming follow-up: #612

Verification

Relevant projects build successfully; focused response/execution tests passed (88 passed, 1 pre-existing skip). git diff --check is clean.

@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown

Test Results

    9 files      9 suites   13m 21s ⏱️
  765 tests   760 ✅  5 💤 0 ❌
2 295 runs  2 280 ✅ 15 💤 0 ❌

Results for commit e3883fd.

♻️ This comment has been updated with latest results.

Change GQLResponse.Data to Skippable<Output voption>, replacing the
previous nullable-obj-based Direct/DeferredErrors/SubscriptionErrors
payload representation with an explicit voption. Propagate the
necessary changes to callers that construct or pattern-match these
response cases (Execution.fs, GraphQLRequestHandler.fs) and to the
ensureDirect test helper (ErrorHelpers.fs), which is split into
ensureDirect/ensureDirectNullData to keep its ValueSome/ValueNone
matching meaningful. Includes only the narrowly required adaptation
in GraphQLWebsocketMiddleware.fs (pattern-match updates from null/bare
data to ValueNone/ValueSome plus ValueOption.toObj conversions at call
sites into the still-nullable-based SubscriptionExecutionResult API)
so the AspNetCore project continues to compile against this contract
change; no other WebSocket lifecycle/serialization behavior is
touched. IO.fs is carried whole because its Fantomas record-brace
reformatting is entangled with the voption change across every
GQLExecutionResult static member; splitting it further would leave a
non-compiling intermediate file.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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

Trace logging in GraphQLRequestHandler still serializes the new Output voption wrapper directly, which can produce misleading logs (and may be incompatible with configured JSON converters) rather than the actual GraphQL data payload.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR updates the server’s GraphQL response contract to make data explicitly skippable vs present-null by changing GQLResponse.Data to Skippable<Output voption>, and then threads that three-state semantics through execution results, transport layers, and tests.

Changes:

  • Updated core response/result DU/record shapes (GQLResponse, GQLResponseContent, deferred/subscription error payloads) to use voption for nullability and Skippable for presence.
  • Propagated the new contract through executor/result shaping and ASP.NET Core HTTP + WebSocket response construction.
  • Refactored/updated tests and test helpers to assert ValueNone (present-null) vs Skip (absent) consistently.
File summaries
File Description
tests/FSharp.Data.GraphQL.Tests/TaskSeqFieldTests.fs Updates assertions for “root data becomes null” cases using ensureDirectNullData and ValueNone deferred error data.
tests/FSharp.Data.GraphQL.Tests/Relay/ConnectionTests.fs Adjusts Direct pattern matches to require ValueSome data and explicitly fail on ValueNone.
tests/FSharp.Data.GraphQL.Tests/MutationTests.fs Updates mutation result matching for Direct (ValueSome data, errors) with explicit failure on null data.
tests/FSharp.Data.GraphQL.Tests/LazyEnumerationExceptionTests.fs Switches to ensureDirectNullData when enumeration failure propagates to root-null data.
tests/FSharp.Data.GraphQL.Tests/ExecutorMiddlewareTests.fs Updates Direct matching to handle ValueSome vs ValueNone.
tests/FSharp.Data.GraphQL.Tests/ExecutionTests.fs Updates error-path tests to assert Direct + null root data via ensureDirectNullData.
tests/FSharp.Data.GraphQL.Tests/ErrorHelpers.fs Introduces ensureDirectNullData and tightens ensureDirect to ValueSome only.
tests/FSharp.Data.GraphQL.Tests/DeferredTests.fs Updates deferred error payload expectations to ValueNone for “no data” incremental error payloads.
src/FSharp.Data.GraphQL.Server/IO.fs Core API change: GQLResponse.Data : Skippable<Output voption> and propagation to Direct/deferred/subscription content cases.
src/FSharp.Data.GraphQL.Server/Executor.fs Converts Direct result Output voption into nullable Output for GQLExecutionResult.Direct construction.
src/FSharp.Data.GraphQL.Server/Execution.fs Updates deferred/subscription error payload construction to use obj voption / Output voption consistently.
src/FSharp.Data.GraphQL.Server.AspNetCore/GraphQLWebsocketMiddleware.fs Updates WebSocket execution/deferred/subscription flows to use ValueNone/ValueSome and ValueOption.toObj where needed.
src/FSharp.Data.GraphQL.Server.AspNetCore/GraphQLRequestHandler.fs Updates HTTP response construction to pass ValueOption.toObj into GQLResponse.Direct; updates deferred/subscription pattern matches for voption.
RELEASE_NOTES.md Documents the breaking signature changes to voption-based nullability in result/response types.
Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/FSharp.Data.GraphQL.Server.AspNetCore/GraphQLRequestHandler.fs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

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

GQLExecutionResult.Empty currently passes Map.empty where Output is IDictionary<string,obj>, which should not type-check and indicates an incorrect empty-output construction.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/FSharp.Data.GraphQL.Server/IO.fs

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.

🟢 Approval recommended

The diff consistently applies the new “skippable vs null” data contract across execution/transport paths and updates tests/helpers to assert the intended semantics without leaving mixed representations behind.

Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@xperiandri xperiandri changed the title Make GraphQL response data skippable Declare that GraphQL response data can be optional and skippable Sep 18, 2026
@xperiandri
xperiandri merged commit 0581b0b into dev Sep 18, 2026
8 checks passed
@xperiandri
xperiandri deleted the graphql-response-data-skippable branch September 18, 2026 21:46
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.

3 participants