9368d77bc8
Implements the `latestSchema` query to fetch the latest schema updates for an organization. This change enhances the GraphQL API by allowing clients to retrieve the most recent schema version and its associated subgraphs. The resolver performs necessary access checks, logs relevant information, and generates the Cosmo router configuration from fetched subgraph SDLs, returning structured schema update details.
107 lines
2.8 KiB
Go
107 lines
2.8 KiB
Go
package graph
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"gitlab.com/unboundsoftware/schemas/graph/model"
|
|
)
|
|
|
|
// GenerateCosmoRouterConfig generates a Cosmo Router execution config from subgraphs
|
|
// using the official wgc CLI tool via npx
|
|
func GenerateCosmoRouterConfig(subGraphs []*model.SubGraph) (string, error) {
|
|
if len(subGraphs) == 0 {
|
|
return "", fmt.Errorf("no subgraphs provided")
|
|
}
|
|
|
|
// Create a temporary directory for composition
|
|
tmpDir, err := os.MkdirTemp("", "cosmo-compose-*")
|
|
if err != nil {
|
|
return "", fmt.Errorf("create temp dir: %w", err)
|
|
}
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
// Write each subgraph SDL to a file
|
|
type SubgraphConfig struct {
|
|
Name string `yaml:"name"`
|
|
RoutingURL string `yaml:"routing_url,omitempty"`
|
|
Schema map[string]string `yaml:"schema"`
|
|
Subscription map[string]interface{} `yaml:"subscription,omitempty"`
|
|
}
|
|
|
|
type InputConfig struct {
|
|
Version int `yaml:"version"`
|
|
Subgraphs []SubgraphConfig `yaml:"subgraphs"`
|
|
}
|
|
|
|
inputConfig := InputConfig{
|
|
Version: 1,
|
|
Subgraphs: make([]SubgraphConfig, 0, len(subGraphs)),
|
|
}
|
|
|
|
for _, sg := range subGraphs {
|
|
// Write SDL to a temp file
|
|
schemaFile := filepath.Join(tmpDir, fmt.Sprintf("%s.graphql", sg.Service))
|
|
if err := os.WriteFile(schemaFile, []byte(sg.Sdl), 0o644); err != nil {
|
|
return "", fmt.Errorf("write schema file for %s: %w", sg.Service, err)
|
|
}
|
|
|
|
subgraphCfg := SubgraphConfig{
|
|
Name: sg.Service,
|
|
Schema: map[string]string{
|
|
"file": schemaFile,
|
|
},
|
|
}
|
|
|
|
if sg.URL != nil {
|
|
subgraphCfg.RoutingURL = *sg.URL
|
|
}
|
|
|
|
if sg.WsURL != nil {
|
|
subgraphCfg.Subscription = map[string]interface{}{
|
|
"url": *sg.WsURL,
|
|
"protocol": "ws",
|
|
"websocket_subprotocol": "graphql-ws",
|
|
}
|
|
}
|
|
|
|
inputConfig.Subgraphs = append(inputConfig.Subgraphs, subgraphCfg)
|
|
}
|
|
|
|
// Write input config YAML
|
|
inputFile := filepath.Join(tmpDir, "input.yaml")
|
|
inputYAML, err := yaml.Marshal(inputConfig)
|
|
if err != nil {
|
|
return "", fmt.Errorf("marshal input config: %w", err)
|
|
}
|
|
if err := os.WriteFile(inputFile, inputYAML, 0o644); err != nil {
|
|
return "", fmt.Errorf("write input config: %w", err)
|
|
}
|
|
|
|
// Execute wgc router compose
|
|
// wgc is installed globally in the Docker image
|
|
outputFile := filepath.Join(tmpDir, "config.json")
|
|
cmd := exec.Command("wgc", "router", "compose",
|
|
"--input", inputFile,
|
|
"--out", outputFile,
|
|
"--suppress-warnings",
|
|
)
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return "", fmt.Errorf("wgc router compose failed: %w\nOutput: %s", err, string(output))
|
|
}
|
|
|
|
// Read the generated config
|
|
configJSON, err := os.ReadFile(outputFile)
|
|
if err != nil {
|
|
return "", fmt.Errorf("read output config: %w", err)
|
|
}
|
|
|
|
return string(configJSON), nil
|
|
}
|