This tutorial is part of Cosmo Connect and focuses on deploying a Router Plugin.
Prerequisites
- Cosmo CLI (minimum version: 0.90.1) installed and configured
- Cosmo Router (minimum version: 0.242.0) installed and configured to use Cosmo Cloud
Overview
gRPC plugins are a powerful new way to write and deploy subgraphs without the need for a GraphQL server. You can use plugins to wrap legacy APIs, mock future subgraphs or fully implement new features. Plugins are written in Go and can be deployed and run automatically by the Cosmo Router. For this tutorial, we’ll create a gRPC plugin calledstarwars
that wraps a small portion of the REST API from SWAPI. SWAPI is a free and open-source public API that provides information about Star Wars characters, planets, and more. For the tutorial, it functions as a stand-in for your own API or external datasource (an SQL database, Stripe, etc.).
gRPC plugins support all the same features as gRPC services, but you don’t have to create separate deployments, handle networking, or manage inter-service authentication.
Here’s a short version of the steps for reference:
1
Initialize a new plugin
Create a new gRPC plugin using
wgc router plugin init <name>
and define your GraphQL schema.→ Jump to initialization2
Design your schema
Define your GraphQL schema that will be used to integrate your plugin into your federated graph.→ Jump to schema design
3
Generate & Implement
Generate Protobuf code with
wgc router plugin generate
and implement your resolvers in Go.→ Jump to implementation4
Publish & Deploy
Publish your plugin to Cosmo with
wgc router plugin publish
and test via GraphQL queries.→ Jump to deploymentSetting up the CLI
Before we start, we should make sure that your version of our CLIwgc
is up to date and you’re logged in.
Check your version with:
This needs to be
>=0.90.1
for the tutorial to work correctly.Building Plugins
First off, let’s get familiar with some terminology we use to describe different parts of the platform:- Cosmo Cloud: Our cloud-hosted platform for publishing and monitoring your subgraphs
- Supergraph: The unified graph containing the composition of all your subgraphs
- Subgraph: A small part of a supergraph, usually serving a small service contract. For example, “billing”
- gRPC Subgraph: A subgraph built with our new gRPC-based tooling that can be run standalone or as a gRPC plugin
- gRPC Plugin: A way to run subgraphs created with gRPC alongside the router directly in your infrastructure, no extra deployment required
Initialize Plugin
You can create a gRPC plugin using our CLI tool,wgc
:
starwars
. We’ll go over what each file does soon.
Design your schema
The first thing we need to do is take a look at the GraphQL schema instarwars/src/schema.graphql
. It doesn’t contain our schema yet, so we’ll start by defining our new service in GraphQL terms.
When you open this file, it will have some placeholder schema inside. You can safely remove all of the content and replace it with the following:
src/schema.graphql
people
resource and its endpoints.
This schema has a single type, “Person”, and a query to get all the people or a specific person by ID.
Generate and Implement
Now we can usewgc
again to generate the Protobuf representation of our subgraph and boilerplate code to implement it in Golang.
generated
folder.
We recommend checking this folder into version control (e.g. Git).
main.go
, you will see some errors about undefined types. These are remnants from the example schema’s resolver, and you can safely delete them to start from scratch.
Here’s a starting point for implementing our new resolvers:
main.go
main.go
that comes with the initial plugin template in a few ways:
- Initialize an instance of the httpclient provided by our
router-plugin
package. This client comes with special features for forwarding telemetry through the router. - We pass the new
client
to theStarwarsService
constructor. - In the
StarwarsService
struct, we added a field of type*httpclient.Client
- This will hold a persistent HTTP client that our endpoints can use for the whole lifetime of the plugin process.
- We removed resolvers for the old
QueryHello
RPC and a fieldnextId
in theStarwarsService
struct.
people
query because of the panic("not implemented")
in the RPC resolver. The plugin would be automatically restarted, but the request would fail. Let’s fix that.
In the
main()
function, you can use os.Getenv
or many available configuration libraries for Go to pull info from the environment to configure your service. A good one to start with is caarlos0/env.main.go
QueryPeople
RPC. Right now, your resolver should look like this:
main.go
QueryPeople
RPC resolver:
main.go
- Start by sending up a request to fetch the list of people from the SWAPI with HTTP GET to
/people
. - Check the response status code and return an error if it’s not 200 OK.
- Decode the JSON response into a slice of
SWAPIPerson
structs. - Transform the slice of
SWAPIPerson
structs into a slice of*service.Person
structs (this type comes from the generated code for your schema)- In a more complex program, this is where you would do any transformations needed to produce the expected response from your backend, database, or other source.
- This method lets you write the GraphQL schema for your client‑facing federated graph in a way that fits that ecosystem, while handling translation from other formats in a fully featured language like Go.
- Finally, we return a response containing the converted people objects
The errors here come from
google.golang.org/grpc/status
and google.golang.org/grpc/codes
. They’re an idiomatic way to return errors in a gRPC API.Publish and Deploy
Now, our plugin is in a semi-working state, and we can publish it to test it out as part of our federated graph. Using our CLIwgc
, publish the plugin:
How does deployment work?
How does deployment work?
When you run the deploy command, your plugin is built and packaged using the
Dockerfile
in the plugin directory. We then send this image containing your plugin and any other files it may need off to our Cosmo Cloud Registry where it can be pulled by your routers.Importantly, the router does not run plugins using Docker or in a container, instead we unpack the final target of the image into a working directory and run the plugin directly. This means if your plugin depends on a system dependency, it must be present in your Router image, not the plugin image.people
via GraphQL.
graphql query
json response
If you get an error, check your router logs to see where it might be coming from. If you can’t solve it, a complete version of the plugin is linked in the Appendix.
Updating the plugin
You can update the schema or the implementation of the plugin by modifying theschema.graphql
file or the main.go
file, respectively.
If you update the schema, you need to regenerate the code by running wgc router plugin generate
.
What’s next?
You can find the full technical documentation for gRPC plugins here. Well, in our case, the SWAPI has much more information than just people. It also includes data about vehicles, planets, and species. We could add these entities to our schema and resolve them using our plugin. In your case, you might add entity resolvers to your plugin’s GraphQL schema to see how federation works with gRPC, or create more plugins for other purposes. Plugins aren’t just for wrapping HTTP APIs either; you can use the full power of Go to query databases, implement business logic, or do anything else you need. You can also implement tests for your plugin to ensure it works correctly, you can find an example test in thesrc/main_test.go
, you can try updating it to work with the new schema.
Appendix
Full plugin code
Full plugin code
src/schema.graphql
src/main.go