Skip to content

Conversation

@JoseSzycho
Copy link
Collaborator

@JoseSzycho JoseSzycho commented Dec 3, 2025

Summary

Introduces a GraphQL Gateway that dynamically exposes Milo APIServer REST/OpenAPI services as a unified GraphQL API using Hive Gateway.

What's Included

Core Gateway

  • Dynamic supergraph composition from OpenAPI specs fetched at runtime via /openapi/v3
  • mTLS authentication using kubeconfig client certificates for secure K8s API communication
  • Automatic polling for schema recomposition (configurable interval, default 20 min)
  • Scoped resource endpoints for querying within Organizations/Projects

Endpoints

Endpoint Description
/graphql Root GraphQL endpoint
/healthcheck Liveness probe
/readiness Readiness probe
/{apiGroup}/{version}/{kind}s/{name}/graphql Scoped queries

Kubernetes Deployment

  • Deployment manifest with 2 replicas and rolling updates
  • cert-manager CSI driver integration for automatic certificate provisioning
  • Service and HTTPRoute for ingress

Developer Experience

  • Local testing script (scripts/local-test.sh) with automatic cert generation
  • Multi-stage Dockerfile
  • TypeScript with path aliases
  • ESLint + Prettier configuration

Architecture

Client → GraphQL Gateway → [mTLS] → Milo APIServer
              │
              └── Hive Gateway Runtime
                  └── Dynamic OpenAPI → GraphQL composition
Screenshot 2025-12-03 at 3 32 54 PM

Configuration

Variable Description Default
KUBECONFIG Path to kubeconfig Required
PORT Server port 4000
POLLING_INTERVAL Schema refresh (ms) 120000
LOGGING Log level info

Testing

# Local testing (requires kubectl access to staging)
./scripts/local-test.sh

Status

Checklist

  • Gateway server implementation on staging
  • Dynamic supergraph composition
  • mTLS authentication
  • Scoped resource endpoints
  • Health probes
  • K8s manifests
  • Local testing script
  • Documentation

Closes datum-cloud/milo#440

- Removed the build stage from the Dockerfile, directly copying the generated supergraph.graphql file.
- Updated .dockerignore and .gitignore to exclude supergraph.graphql from version control.
…M, Notification, and ResourceManager"

This reverts commit 6d44dac.
…rignore and .gitignore to include dist directory
…uthentication, and local testing enhancements
@JoseSzycho
Copy link
Collaborator Author

@zachsmith1 Thank you for all of your feedback during the designing process

@drewr
Copy link

drewr commented Dec 15, 2025

We need an npm install in here... but after I did that things seemed to work. Test script was a great addition, thanks!

% scripts/local-test.sh
[...]
> graphql-gateway@1.0.0 dev
> tsx src/gateway/index.ts


node:internal/modules/run_main:123
    triggerUncaughtException(
    ^
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@graphql-hive/gateway' imported from /home/drewr/src/datum-cloud/graphql-gateway/src/gateway/runtime/index.ts
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:314:9)
    at packageResolve (node:internal/modules/esm/resolve:767:81)
    at moduleResolve (node:internal/modules/esm/resolve:853:18)
    at defaultResolve (node:internal/modules/esm/resolve:983:11)
    at nextResolve (node:internal/modules/esm/hooks:748:28)
    at resolveBase (file:///nix/store/l1ggya22xf8sfgamqysbs23q3mmg4a23-tsx-4.19.3/lib/tsx/dist/esm/index.mjs?1765834252510:2:3212)
    at resolveDirectory (file:///nix/store/l1ggya22xf8sfgamqysbs23q3mmg4a23-tsx-4.19.3/lib/tsx/dist/esm/index.mjs?1765834252510:2:3584)
    at resolveTsPaths (file:///nix/store/l1ggya22xf8sfgamqysbs23q3mmg4a23-tsx-4.19.3/lib/tsx/dist/esm/index.mjs?1765834252510:2:4073)
    at async resolve (file:///nix/store/l1ggya22xf8sfgamqysbs23q3mmg4a23-tsx-4.19.3/lib/tsx/dist/esm/index.mjs?1765834252510:2:4441)
    at async nextResolve (node:internal/modules/esm/hooks:748:22) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v22.21.1

Copy link

@drewr drewr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't officially approve without a closer look, but this is great work @JoseSzycho!

@gaghan430
Copy link

@JoseSzycho In the ticket, the listed deliverables include GraphQL schema additions and resolver implementations. However, I don’t see a sample resolver implementation here.

For example, if we have a query like:

listNotificationMiloapisComV1alpha1NamespacedContactGroupMembership(
  namespace: ""
) {
  items {
    spec {
      contactRef {
        name
        namespace
      }
    }
  }
}

How do we retrieve the actual contact details (e.g., familyName, givenName, etc.) from this reference? I just want to make sure I’m not missing something. But great work!

@JoseSzycho
Copy link
Collaborator Author

@drewr Thanks! Already fixed the code adding missing npm install. Great catch there

@JoseSzycho
Copy link
Collaborator Author

@ggaghan430 thanks for the feedback! We should have updated the issue earlier.

We decided to change the implementation and make each GraphQL consumer responsible for implementing its own resolvers and type generation.

In this PR, you can see how to auto-generate the types and queries consumed from the GraphQL gateway:
datum-cloud/staff-portal#264

Here, we define the custom queries we need:
https://github.com/datum-cloud/staff-portal/blob/249/notes-integration/app/resources/graphql/queries/notes.graphql
All autogenerated types are then generated using bun codegen.

It is important to have the process.env.GRAPHQL_URL environment variable set, as the codegen process performs schema introspection against the GraphQL gateway. This is beneficial because if the API is updated and your custom queries become outdated, the generation step will fail with an error.

Once the code has been generated, you can implement the requests. Here is an example:
https://github.com/datum-cloud/staff-portal/blob/249/notes-integration/app/resources/request/client/note.request.ts

This is the approach I came up with. I do not have extensive front-end experience, so please feel free to suggest improvements or propose changes to the current GraphQL implementation.

@gaghan430
Copy link

@JoseSzycho Sorry if my question wasn’t very clear earlier :D.
What I meant by schema additions is the ability to do something like this:
https://the-guild.dev/graphql/mesh/v1/schema-extensions
Please have a look at that page, it has a good example and should give a better idea of where I’m coming from.

@JoseSzycho
Copy link
Collaborator Author

@gaghan430 At the moment, we are not supporting schema additions or extensions like the ones described in the GraphQL Mesh documentation. The current scope is limited to providing an auto-generated GraphQL layer based on the existing OpenAPI specifications exposed by Milo.

We could create a issue for tackling this in the future

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.

Notes Integration - Define the GraphQL Layer for Contact Notes

4 participants