Cosmo Connect Unveils TypeScript Plugin Support for Router Extension

development

Cosmo Connect now offers TypeScript plugin support, empowering teams to extend its GraphQL router directly with custom logic. This streamlines integrating legacy APIs and services for TypeScript-centric teams, eliminating the need for Go or separate microservices, all managed through Cosmo Cloud with robust schema checks.

Cosmo Connect now offers comprehensive TypeScript plugin support, enabling developers to extend its router functionality entirely with TypeScript. This eliminates the need to introduce Go or maintain separate microservices for custom logic, especially beneficial for teams already deeply integrated with TypeScript codebases. The plugins execute directly within the router, are managed via Cosmo Cloud, and undergo the same rigorous schema checks as any other subgraph, streamlining development and deployment workflows.

Getting Started with TypeScript Plugins

The introduction of TypeScript plugin support for Cosmo Connect allows you to write plugins in TypeScript and load them directly into the router, bypassing the need for a separate service. This simplifies the process of exposing small pieces of business logic, wrapping legacy API calls, or integrating internal services behind your GraphQL contract.

Previously, Cosmo Connect router plugins were exclusively available in Go. While suitable for Go-centric teams, this posed a barrier for others. By supporting TypeScript, a language widely used by developers, the plugin workflow becomes significantly more accessible, allowing more teams to leverage its benefits. This is particularly useful for scenarios where teams want to expose a minor logic component or integrate a legacy REST API without the overhead of deploying an additional service. A TypeScript plugin enables you to model a GraphQL type, invoke an internal API, transform the response, and expose it via the router with minimal operational complexity, effectively behaving like a subgraph without the associated deployment costs.

Why TypeScript Plugins Matter

TypeScript plugins don't introduce new capabilities beyond what Go plugins offer; instead, they democratize the existing plugin workflow. From a platform perspective, this feature significantly boosts adoption and accessibility. Engineers already proficient in TypeScript can immediately begin using plugins without the prerequisite of learning Go.

In a typical federated setup, each subgraph operates as its own service with independent deployment. Router plugins allow you to embed some of this logic directly into the router. This is particularly advantageous when creating a new "subgraph" without deploying an entire service, or when bridging legacy systems that don't natively communicate with GraphQL.

When initializing a plugin, you can now specify ts as the language option, for example:

wgc router plugin init planets --language ts

Upon publishing the plugin and updating the subgraph, it undergoes the same composition and schema checks as all other elements within Cosmo, ensuring consistency and integrity. Similar to Go plugins, TypeScript plugins are fully supported in the Cosmo Cloud Plugin Registry, enabling direct push to Cosmo Cloud for automatic distribution to all running router instances.

Why TypeScript Shipped After Go

Cosmo Connect's plugin architecture originated with Go, largely because the router itself is written in Go, and it leverages HashiCorp's go-plugin library for seamless plugin loading and management. This setup provides a "batteries included" experience for Go, handling much of the low-level mechanics automatically.

TypeScript support required more extensive development due to the absence of an equivalent, fully packaged runtime for TS plugins. WunderGraph undertook more of the internal "plumbing" to ensure TypeScript plugins offer the same integrated feel as their Go counterparts, explaining why Go support was released first.

Initializing a TypeScript Plugin

Here's a quick overview of implementing a TypeScript plugin. For a comprehensive guide, refer to the full plugin tutorial in the official documentation.

Start by initializing a Cosmo Connect TypeScript plugin using the CLI. This scaffolds the basic project structure.

wgc router plugin init my-ts-plugin --language ts

Cosmo Connect generates protobuf definitions from your GraphQL schema. After scaffolding, you need to generate these definitions and the corresponding protobuf code.

wgc router plugin generate my-ts-plugin

These commands establish a minimal plugin project with a basic TypeScript plugin server. You can then begin editing the GraphQL schema within the plugin directory.

After executing the two commands, your project structure will resemble:

my-ts-plugin/ ├── src/ │ ├── plugin.ts │ └── plugin-server.ts ├── schema/ │ └── schema.graphql ├── proto/ │ └── service.proto ├── tsconfig.json └── package.json

The hashicorp-go library provides helpers for initializing a plugin server. WunderGraph has implemented similar helpers in plugin-server.ts, which include:

  • Initializing gRPC health checks
  • Establishing the handshake between the router and plugin

The plugin.ts file serves as the entry point for your plugin, where you implement RPC handlers such as queryHello and the new queryPlanet method.

Adding a GraphQL Schema

Next, update the schema.graphql file inside your plugin directory. For example:

type Query {
  hello: String!
  planet: Planet!
}

type Planet {
  name: String!
  description: String
}

Any changes to these types necessitate regenerating the protobuf definitions to ensure the plugin code has access to the new fields and operations.

Generating Protobuf Types

After updating the schema, regenerate the protobuf types:

wgc router plugin generate my-ts-plugin

This command utilizes WunderGraph's internal protographic tool to compile the schema into protobuf definitions that the router can understand. You can observe this change by examining service.proto in the generated proto directory before and after running the command. Initially, service.proto contains only the original World and hello RPC definitions; post-generation, the new Planet message and RPC (QueryPlanet) will appear.

Implementing the Plugin Logic

You implement both RPC handlers within src/plugin-server.ts, alongside the existing QueryHello handler.

The existing queryHello RPC:

// src/plugin-server.ts
const queryHello = async (request: { name: string }): Promise<{ greeting: string }> => {
  return { greeting: `Hello, ${request.name || 'World'}!` };
};

Then add the new queryPlanet RPC for planet: Planet!:

// src/plugin-server.ts
const queryPlanet = async (): Promise<{ name: string; description: string }> => {
  return {
    name: "Earth",
    description: "Our home planet in the Solar System."
  };
};

This constitutes the core business logic. The router automatically converts the protobuf response back into GraphQL. In a production scenario, this section would typically involve calls to an internal HTTP service, legacy API, or database.

Building the Plugin

Build the plugin using the command:

wgc router plugin build my-ts-plugin

A successful build generates a plugin artifact, which can be verified in the bin folder of your plugin. This folder will contain a binary whose name is specific to your operating system and architecture (e.g., darwin-arm64 for an M1 Mac).

Publishing the Plugin

The next step is to publish the plugin to Cosmo Cloud, making it available for your router instances.

Publish it to Cosmo Cloud:

wgc router plugin publish my-ts-plugin --namespace your-namespace

This command uploads the plugin to Cosmo Cloud for the specified namespace.

Then, update the subgraph metadata:

wgc subgraph update --namespace your-namespace --name your-subgraph --plugin my-ts-plugin

Updating the subgraph metadata signals routers within the namespace to reload and pull the new plugin, ensuring the new planet field becomes part of the schema they serve.

Querying the Router

Once the router reloads and integrates the updated plugin, the planet field will be available in the GraphQL playground schema.

query {
  planet {
    name
    description
  }
}

It returns:

{
  "data": {
    "planet": {
      "name": "Earth",
      "description": "Our home planet in the Solar System."
    }
  }
}

Schema Checks and Observability

When publishing a TypeScript plugin and updating the subgraph:

  • Normal composition rules apply.
  • No additional checks are required specifically for TypeScript plugins.

For observability:

  • You can test your plugin logic directly in the Playground.
  • TypeScript plugins currently do not include built-in tracing.

Conclusion

A highly effective initial experiment involves creating a TypeScript plugin to wrap a single REST endpoint. Define the GraphQL type, map it within your handler, publish the plugin through Cosmo Cloud, update the subgraph metadata, and then query it in the Playground. This provides a valuable, end-to-end understanding of the workflow in a real-world environment.

The complete workflow involves defining the schema, generating protobufs, implementing handlers in TypeScript, building, publishing, and witnessing the automatic router reload upon completion. This significantly simplifies integrating small logic components or legacy services into your GraphQL graph without the need for deploying additional subgraphs.

For a more comprehensive guide on building plugins, consult the full plugin tutorial in the official documentation.