Custom Modules
Customize your router by writing just a few lines of Go code and compiling it with a single command. Eliminate the complexities associated with writing scripts and use the existing Go ecosystem.
In order to complete this section you need to have Golang 1.20 (or higher) and docker installed.
The Cosmo Router can be easily extended by providing custom modules. Modules are pure Go code and can implement one or multiple interfaces. The following interfaces are provided:
core.RouterMiddlewareHandler
Implements a custom middleware on the router. The middleware is called for every client request. It allows you to modify the request before it is processed by the GraphQL engine. Use case: Logging, Caching, Early return, Request Validation, Header manipulation.core.EnginePreOriginHandler
Implements a custom handler that is executed before the request is sent to the subgraph. This handler is called for every subgraph request. Use case: Logging, Header manipulation.core.EnginePostOriginHandler
Implement a custom handler executed after the request to the subgraph but before the response is passed to the GraphQL engine. This handler is called for every subgraph response. Use cases: Logging, Caching.core.Provisioner
Implements a Module lifecycle hook that is executed when the module is instantiated. Use it to prepare your module and validate the configuration.core.Cleaner
Implements a Module lifecycle hook that is executed after the server is shutdown. Use it to close connections gracefully or for any other cleanup.
*OriginHandler
handlers are called concurrently when your GraphQL operation results in multiple subgraph requests. Due to that circumstance, you should handle the initial router request/response objects ctx.Request()
and ctx.ResponseWriter()
as read-only objects. Any modification without protecting them from concurrent writes, e.g., by a mutex, results in a race condition.
Example
The example below shows how to implement a custom middleware that has access to the GraphQL operation information.
Priority Loading of Modules
When loading multiple modules, the order is not inherently guaranteed. To ensure a specific loading order, you can use the Priority
option. Modules with lower priority numbers are loaded first. Below is an example configuration:
In this example, the module myModule
has a priority of 1, meaning it will be loaded before modules with higher priority values.
Access the GraphQL operation
During the client request, you have access to the actual GraphQL operation. Simply call:
Access Request Context
In every handler, you can add/remove, or modify response headers. We also provide a convenient, safe way to share data across handlers.
Access Subgraph through Request Context
Through the request context you can retrieve the active subgraph for the current request. This can be done in the OnOriginRequest hook as show below
A more complex example including tests is accessible at https://github.com/wundergraph/cosmo/tree/main/router/cmd/custom
Access authentication information
Authentication information, including claims and the provider that authenticated the request, can be accessed through core.RequestContext.Authentication()
For a full example, please check out https://github.com/wundergraph/cosmo/tree/main/router/cmd/custom-jwt
Return GraphQL conform errors
Please always use core.WriteResponseError
to return an error. It ensures that the request is properly tracked for tracing and metrics.
Request Handler lifecycle
The current module handler allow to intercept and modify request / response subgraphs.
Module Configuration
If you need to pass external configuration values to your module, you can do so easily by annotating the fields in your module struct. Fields must start with an uppercase letter to make them accessible.
Example Config file
Based on the example above we will populate the field Value
with the value 1
. You can also validate your config in the core.Provisioner
handler.
Development
Due to the circumstance that modules are pure Go code, we can leverage all tooling. If you have VSCode or Goland you can easily debug and profile your code. Let's make it running locally first:
Clone the Cosmo Repository
Navigate to the router directory
Copy
.env.example
to.env
and fill in all required values.Run
go run cmd/custom/main.go
to start your router or use your IDE to start the debug mode.Open http://localhost:3002 to test your module code.
Build your own Router Image
We provide a dockerfile that can be used to build a production-grade docker image from your custom router. Run the following command in the router directory.
In order to start your router run:
Versioning
Please ensure that you checkout on an official router tag when extending the router, and only upgrade if necessary. This way, you can avoid any surprises. For every release, we provide detailed release notes that should provide you with a good overview of whether an upgrade is worthwhile.
Please inform us if you have more advanced use cases that cannot be accommodated with the current feature set.
Last updated