refactor: replace REST/OpenAPI management API with GraphQL (gqlgen) - #42
Merged
Conversation
Rewrite the management API (functions, versions, executions, tokens) from a hand-maintained REST/OpenAPI surface to GraphQL via gqlgen. The schema in internal/graph/schema is the single source of truth: resolvers are generated interfaces, so the compiler enforces the contract and it can't drift. Server: - gqlgen at POST /graphql (auth-protected) + GraphiQL at GET /graphql, wired as its own fx module; GraphQL types bound directly to internal/store (no DTOs). - Lazy field resolvers for envVars/scopedData/globalData (the overfetch fix), a Map scalar, a CronStatus enum, and relation edges making the graph traversable both ways (Function.versions/executions/nextRun, Execution.function/version/ logs/aiRequests/emailRequests, and reverse edges). - Removed all REST /api/* management routes and handlers, the hand-written openapi.yaml, and Swagger /docs; shared validation moved to internal/validation. /fn/* execution and /api/auth/* (login + device flow) stay REST by design. CLI: - lunar-cli now talks GraphQL via hasura/go-graphql-client with hand-written commands, replacing oapi-codegen and the custom Cobra generator. Frontend: - api.js is a thin GraphQL anti-corruption layer; detail views use combined queries to cut round-trips (execution-detail goes from 5 to 1). Docs/tooling: - ADR-0012, docs/rest-endpoints.md, README updates, a mise seed task, and generate-graphql replacing generate-cli.
Two breakages surfaced once the integration module actually compiled:
- go.sum was missing 99designs/gqlgen (the server now imports it) and still
referenced the removed oapi-codegen/runtime. `go mod tidy` on the nested
lunar-cli/integration module adds the former and drops the latter, fixing the
"missing go.sum entry" setup failure.
- The in-memory test DB used a plain ":memory:" DSN, which is private per pooled
connection. The GraphQL server resolves sibling fields (envVars/scopedData/
globalData) concurrently, so the pool handed out fresh, unmigrated connections
("no such table"). Pin the pool to a single connection so every query uses the
one migrated database.
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.
Summary
Rewrites the management API (functions, versions, executions, tokens) from a hand-maintained REST/OpenAPI surface to GraphQL via gqlgen. The schema in
internal/graph/schemais the single source of truth: resolvers are generated interfaces bound directly tointernal/store(no DTOs), so the compiler enforces the contract and it can't drift./fn/*execution and/api/auth/*(login + device flow) intentionally stay REST.Server
POST /graphql(auth-protected) + GraphiQL atGET /graphql, wired as its ownfxmodule.envVars/scopedData/globalData(the overfetch fix), aMapscalar, and aCronStatusenum.Function.versions/executions/nextRun,Execution.function/version/logs/aiRequests/emailRequests, and reverse edges (FunctionVersion.function,AIRequest/EmailRequest.execution)./api/*management routes/handlers, the hand-writtenopenapi.yaml, and Swagger/docs; shared validation moved tointernal/validation.CLI
lunar-clinow talks GraphQL viahasura/go-graphql-clientwith hand-written commands, replacing oapi-codegen and the custom Cobra generator.Frontend
api.jsis a thin GraphQL anti-corruption layer; detail views use combined queries to cut round-trips (execution-detail: 5 → 1).Docs & tooling
docs/rest-endpoints.md, README updates, a miseseedtask, andgenerate-graphqlreplacinggenerate-cli.Verification
Full server + CLI build/vet/test, e2e (real browser),
golangci-lint(0 issues),deno fmt, and idempotent codegen all green.🤖 Generated with Claude Code