[FEATURE] GraphQL mutation support (operationType, variables payload, errors-in-200 selection)
@jeffreyaven 已经在做这个了。
开始于 2026年9月14日。
评估
这个 Issue 还没有评估数据。
描述
Summary
any-sdk currently supports GraphQL for reads only. The x-stackQL-graphQL extension is modelled by standardGraphQL (internal/anysdk/graphql.go) with id, query, url, httpVerb, cursor, and responseSelection - no operation type and no variables. The only execution path is StandardGQLReader (pkg/graphql/graphql.go), a paginating read loop (cursor strategies: cursor_after, keyset, offset, page_info) whose renderQuery() templates the cursor splice into the query string and posts { "query": "..." }. The REST mutation machinery (isMutation in public/formulation and public/providerinvokers/anysdkhttp) never consults GetGraphQL(), and the static analyzer short-circuits GraphQL methods entirely:
// public/discovery/static_analyzer.go:1448
graphQL := method.GetGraphQL()
if graphQL != nil {
return result // TODO: GraphQL methods analysis
}
The consequence is that all GraphQL-backed providers are SELECT-only by engine constraint, not by provider choice. This issue proposes first-class GraphQL mutation support.
Motivating consumers
gitlab- the intended canonical reference implementation: a strictly Relay-conventional mutation surface (singleinputobject argument,<entity>Create/<entity>Update/<entity>Destroynaming,errors: []payloads inside HTTP 200), free full-lifecycle CI via the gitlab-ce container. A read-only provider for a DevOps platform is a visible gap (issues, MRs, labels, CI variables are write-expected resources).runpod- GraphQL-only vendor whose control operations (pod deploy/start/stop/terminate) are mutations; without this feature the provider is inventory-only.railway- GraphQL-only vendor; deploys/restarts/scaling are mutations.- Write phases of
newrelic(NerdGraph: alert policies, dashboards, tagging) andbuildkite.
Proposed design
-
Model (
internal/anysdk/graphql.go, loader ininternal/anysdk/loader.goviaExtensionKeyGraphQL):operationType(string, optional): absent orquery-> existing reader behaviour;mutation-> one-shot executor. Back-compat: every existing spec is untouched.variables(map, optional): a template map binding method parameters to a GraphQL variables payload, rendered with the sametext/templateinputs the query template receives. Present -> the request body is{ "query": ..., "variables": { ... } }.errorSelection(GraphQLElement, optional): a jsonPath whose resolution to a non-empty array or non-null value marks the call failed, regardless of HTTP 200. This is the GraphQL errors-in-200 convention (both the top-levelerrorsarray and payload-leveluserErrors/errorsfields, selectable per method).responseSelectionretains its current meaning for the mutation payload projection.
-
Executor (
pkg/graphql/): a one-shotGQLExecutoralongsideStandardGQLReader- no cursor loop, renders query + variables, single request, applieserrorSelectionthenresponseSelection. Reuse the client, logging context (ContextWithHTTPLogger), and stream_transform hooks the reader already has.- Note: variables support should also be made available to the read path in a follow-up, replacing the current escape-and-embed rendering in
renderQuery()(pkg/graphql/graphql.go:649) for methods that declarevariables- a robustness improvement independent of mutations.
- Note: variables support should also be made available to the read path in a follow-up, replacing the current escape-and-embed rendering in
-
Invocation wiring: route GraphQL methods with
operationType: mutationthrough the mutation path (theisMutationplumbing inpublic/formulation/formulation.goandpublic/providerinvokers/anysdkhttp/invoker.go) so INSERT/UPDATE/DELETE/EXEC verb mappings insqlVerbsbecome legal for GraphQL methods. -
Static analysis (
public/discovery/static_analyzer.go): retire the TODO at line 1448 with GraphQL method checks -queryparses, template placeholders resolvable from declared parameters,operationType: mutationmethods carryerrorSelection(warning if absent),responseSelectionpresent for selectable methods, cursor config forbidden on mutations.
Spec shape (target)
x-stackQL-graphQL:
url: https://gitlab.com/api/graphql
httpVerb: POST
operationType: mutation
query: >
mutation($input: CreateIssueInput!) {
createIssue(input: $input) {
issue { iid title state webUrl }
errors
}
}
variables:
input:
projectPath: '{{ .full_path }}'
title: '{{ .title }}'
description: '{{ .description }}'
responseSelection:
jsonPath: '$.data.createIssue.issue'
errorSelection:
jsonPath: '$.data.createIssue.errors'
Acceptance criteria
- Existing GraphQL read specs (including the in-repo fixture
internal/anysdk/testdata/registry/src/github/v0.3.1/services/scim.yaml) load and execute byte-identically -operationTypeabsent implies current behaviour. - A mutation method loads via
ExtensionKeyGraphQL, executes one-shot with a variables payload, projectsresponseSelectionon success. - A populated
errorSelectionresult surfaces as a call failure (with the selected content in the error), never as rows - covered by a negative test. - Top-level GraphQL
errorson HTTP 200 also surfaces as failure. - Static analyzer covers GraphQL methods per point 4; the line 1448 TODO is removed.
- Unit tests in
pkg/graphqlfor the executor (success, payload errors, top-level errors, template resolution failure).
Out of scope
- GraphQL subscriptions (streaming - excluded per standing policy).
- Automatic mutation generation from introspection (provider tooling concern -
@stackql/provider-utils). - Cursor/pagination interaction with mutations (forbidden by analyzer rule instead).
- 主要语言
- Go
- 星标
- 0
- 派生
- 1
- 平均合并
- 33 分钟
- 30 天内合并 PR
- 7
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
stackql/any-sdk 的其他 Issue
-
enhancement go
难度 5/5 一周以上 新手友好度 38/100
-
enhancement
难度 3/5 1-2 天 新手友好度 78/100
-
[FEATURE] Carry the naked upstream HTTP status code through the provider invoker boundary可能重新可做 @jeffreyaven 于 112 天前认领,目前没有进行中的 PR。 未关闭enhancement
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
kind/engineering pulumi/pulumi-terraform Task Workflow Failure
难度 2/5 1-3 小时 新手友好度 64/100
pulumi/pulumi-terraform#1261 ·
维护者通常 1 天内回复
-
Controllers integration tests fail when port 8080 is in use可能已有人在做 @noahnut 今天认领。 未关闭area/cluster-autoscaler kind/bug needs-triage
难度 2/5 1-3 小时 新手友好度 78/100
kubernetes-sigs/cluster-autoscaler#236 · 1 条评论 ·
维护者通常 1 天内回复
-
MCP: `tasks_bulk_update` always fails with "Need at least one field" — the `fields` projection argument is stripped from non-read tools too可能已有人在做 @tink-bot 今天认领。 未关闭agent-processed area/api-v2 integration/inbound
难度 2/5 1-3 小时 新手友好度 82/100
go-vikunja/vikunja#4235 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 84/100
google/osv-scalibr#2503 ·
维护者通常 1 天内回复