| name | cosmo-connect |
| description | Create and modify APIs using WunderGraph Cosmo Connect. Covers gRPC plugin development (Go/TypeScript), standalone gRPC services, schema-to-proto workflows, CLI commands (wgc), local router setup, graph.yaml composition, field resolvers, batching, federation entities, and deployment. Use when building Cosmo Connect subgraphs, plugins, gRPC services, or setting up a local Cosmo Router.
|
Cosmo Connect
Cosmo Connect lets you use GraphQL Federation without running GraphQL servers. Define an Apollo-compatible Subgraph Schema, compile it to protobuf, implement it as gRPC.
Decision: Plugin vs gRPC Service
| Factor | Router Plugin | gRPC Service |
|---|
| Languages | Go, TypeScript (Bun) | Any gRPC language |
| Deployment | Co-located with router | Independent microservice |
| Scaling | Coupled to router | Independent |
| Latency | Minimal (IPC) | Network overhead |
| Team autonomy | Low | High |
Use plugins for simple integrations, lowest latency, wrapping legacy APIs.
Use gRPC services for team ownership, independent scaling, language flexibility.
Core Workflow
1. Define GraphQL Schema (standard Subgraph Schema)
2. Generate Protobuf + Mapping (wgc CLI)
3. Implement gRPC logic
4. Configure Router
5. Compose supergraph (wgc router compose)
6. Update README with example queries (see "Example Queries in README" section)
7. Deploy and test
Plugin Workflow
wgc router plugin init my-plugin -p myproject --language go
wgc router plugin init my-plugin -p myproject --language ts
wgc router plugin generate ./my-plugin
wgc router plugin test ./my-plugin
wgc router plugin build ./my-plugin
wgc router plugin publish ./my-plugin
gRPC Service Workflow
wgc grpc-service init --template golang-connect-rpc --directory ./my-service
wgc grpc-service generate -i ./schema.graphql -o ./generated
wgc grpc-service publish my-service --schema ./schema.graphql --generated ./generated
Go Plugin Implementation Pattern
package main
import (
"log"
service "github.com/wundergraph/cosmo/plugin/generated"
routerplugin "github.com/wundergraph/cosmo/router-plugin"
"google.golang.org/grpc"
)
func main() {
pl, err := routerplugin.NewRouterPlugin(func(s *grpc.Server) {
s.RegisterService(&service.MyService_ServiceDesc, &MyServiceImpl{})
})
if err != nil {
log.Fatalf("failed to create router plugin: %v", err)
}
pl.Serve()
}
TypeScript Plugin Implementation Pattern
import * as grpc from '@grpc/grpc-js';
import { MyServiceService, IMyServiceServer } from '../generated/service_grpc_pb.js';
import { PluginServer } from './plugin-server.js';
class MyService implements IMyServiceServer {
[name: string]: grpc.UntypedHandleCall;
queryData(call, callback) {
const response = new QueryResponse();
callback(null, response);
}
}
const pluginServer = new PluginServer();
pluginServer.addService(MyServiceService, new MyService());
pluginServer.serve();
Go gRPC Service Pattern (Connect RPC)
type Service struct{}
func (s *Service) QueryGetProject(ctx context.Context, req *connect.Request[pb.QueryGetProjectRequest]) (*connect.Response[pb.QueryGetProjectResponse], error) {
return connect.NewResponse(&pb.QueryGetProjectResponse{
GetProject: &pb.Project{Id: req.Msg.Id, Name: "My Project"},
}), nil
}
TypeScript gRPC Service Pattern (Connect RPC + Fastify)
import type { ConnectRouter } from "@connectrpc/connect";
import { Service } from "./proto/service/v1/service_pb.js";
export default (router: ConnectRouter) => {
router.service(Service, {
queryGetProject: async (req) => ({
getProject: { id: req.id, name: "My Project" },
}),
});
};
Field Resolvers
For fields with arguments, use @connect__fieldResolver:
type Foo {
id: ID!
bar(baz: String!): String! @connect__fieldResolver(context: "id")
}
Generates a dedicated ResolveFooBar RPC. Batching is automatic.
Critical: Return results in the exact same order as provided context elements.
Local Router Setup (No Cloud)
Set ROUTER_CONFIG_PATH to run in static config mode — no controlplane or API token needed.
wgc router compose -i ./graph.yaml -o ./config.json
ROUTER_CONFIG_PATH=./config.json go run ./cmd/router/main.go
PLUGINS_ENABLED=true PLUGINS_PATH=./plugins
graph.yaml Subgraph Shapes
- name: my-subgraph
routing_url: http://localhost:4001/graphql
schema:
file: ./path/to/schema.graphqls
- name: my-grpc-subgraph
routing_url: dns:///localhost:4011
grpc:
schema_file: ./path/to/src/schema.graphql
proto_file: ./path/to/generated/service.proto
mapping_file: ./path/to/generated/mapping.json
- name: my-plugin-subgraph
plugin:
version: 0.0.1
path: ./path/to/plugin-dir
Router Config (config.yaml)
version: "1"
plugins:
enabled: true
path: "plugins"
GraphQL Feature Support
Supported: Query, Mutation, Entity Lookups (single/multiple/compound keys), Scalar/Complex args, Enums, Interfaces, Unions, Recursive types, Nested objects, Lists, Entity definitions, Key directives, External fields, Field resolvers (with batching).
Not yet supported: Nested key entity lookups, @requires, Subscriptions, Nullable list items (protobuf constraint).
Example Queries in README
After composing the supergraph schema (wgc router compose), always add example queries to the project's README. This lets users immediately copy-paste queries into the playground.
When to generate
After every wgc router compose that succeeds, check the README for an "Example Queries" section and update it to reflect the current composed schema.
How to generate
- Read the composed supergraph config (
config.json) or the individual subgraph schemas to identify all root Query and Mutation fields.
- For each root field, write a minimal but useful example query that includes:
- The operation name (PascalCase matching the field name)
- All required arguments with variables
- A representative selection of return fields (not every field — pick the most useful 3-5)
- For federation entity joins, include the cross-subgraph fields with a comment noting which subgraph resolves them
- Add a variables JSON block for any query/mutation that requires input arguments.
- Group queries before mutations. Lead with the simplest query.
README format
## Example Queries
<description of the query>:
\`\`\`graphql
query OperationName {
fieldName {
field1
field2
field3
}
}
\`\`\`
<description including federation details if applicable>:
\`\`\`graphql
query OperationName($input: InputType!) {
fieldName(arg: $input) {
field1
field2
crossSubgraphField # resolved from <other-subgraph> plugin
}
}
\`\`\`
Variables:
\`\`\`json
{
"input": { ... }
}
\`\`\`
More examples are available in the `examples/` directory.
Rules
- Only include queries/mutations that exist in the composed schema — don't guess.
- Keep each example minimal — show the shape, not every field.
- For union return types, show both
... on SuccessType and ... on ErrorType fragments.
- If an
examples/ directory exists with .graphql files, reference it at the end.
- Don't duplicate the full examples directory content — pick 2-3 representative queries for the README.
References