-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
54 changed files
with
13,896 additions
and
488 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,5 @@ node_modules | |
# docker volumes | ||
**/_docker | ||
tsconfig.tsbuildinfo | ||
gen | ||
#lerna | ||
lerna-debug.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
**/.env | ||
**/.env.local | ||
CHANGELOG.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
router | ||
/router |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
dev: | ||
go run main.go | ||
go run cmd/router/main.go | ||
|
||
test: | ||
go test ./... | ||
|
||
build: | ||
CGO_ENABLED=0 GOOS=linux go build -trimpath -a -o router . | ||
CGO_ENABLED=0 GOOS=linux go build -trimpath -a -o router cmd/router/main.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Custom Router | ||
|
||
This entrypoint serve as an example about how to build your own custom Cosmo Router. | ||
The main.go file is the entrypoint of the router and is responsible for starting the router. | ||
You can see we will load the default Router and your custom module. | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
routercmd "github.com/wundergraph/cosmo/router/cmd" | ||
// Import your modules here | ||
_ "github.com/wundergraph/cosmo/router/cmd/custom/module" | ||
) | ||
|
||
func main() { | ||
routercmd.Main() | ||
} | ||
``` | ||
|
||
## Run the Router | ||
|
||
Before you can run the router, you need to copy the `.env.example` to `.env` and adjust the values. | ||
|
||
```bash | ||
go run ./cmd/custom/main.go | ||
``` | ||
|
||
## Build your own Router | ||
|
||
```bash | ||
go build -o router ./cmd/custom/main.go | ||
``` | ||
|
||
## Build your own Image | ||
|
||
```bash | ||
docker build -f custom.Dockerfile -t router-custom:latest . | ||
``` | ||
|
||
## Run tests | ||
|
||
In order to run the tests, you need to run the example subgraph first. We use the demo subgraph for this. | ||
|
||
``` | ||
make dc-subgraphs-demo | ||
``` | ||
|
||
In practice, you would create a custom router config and mock the subgraph dependencies in your tests. | ||
|
||
_All commands are run from the root of the router directory._ | ||
|
||
## Credits | ||
|
||
The module system is inspired by [Caddy](https://github.com/caddyserver/caddy). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package main | ||
|
||
import ( | ||
routercmd "github.com/wundergraph/cosmo/router/cmd" | ||
// Import your modules here | ||
_ "github.com/wundergraph/cosmo/router/cmd/custom/module" | ||
) | ||
|
||
func main() { | ||
routercmd.Main() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package module | ||
|
||
import ( | ||
"fmt" | ||
"github.com/wundergraph/cosmo/router/pkg/app" | ||
"github.com/wundergraph/cosmo/router/pkg/graphql" | ||
"go.uber.org/zap" | ||
"net/http" | ||
) | ||
|
||
func init() { | ||
// Register your module here | ||
app.RegisterModule(&MyModule{}) | ||
} | ||
|
||
const myModuleID = "myModule" | ||
|
||
// MyModule is a simple module that has access to the GraphQL operation and add a header to the response | ||
// It demonstrates how to use the different handlers to customize the router. | ||
// It also shows how to use the config file to configure and validate your module config. | ||
// By default, the config file is located at `config.yaml` in the working directory of the router. | ||
type MyModule struct { | ||
// Properties that are set by the config file are automatically populated based on the `mapstructure` tag | ||
// Create a new section under `modules.<name>` in the config file with the same name as your module. | ||
// Don't forget in Go the first letter of a property must be uppercase to be exported | ||
|
||
Value uint64 `mapstructure:"value"` | ||
|
||
Logger *zap.Logger | ||
} | ||
|
||
func (m MyModule) Provision(ctx *app.ModuleContext) error { | ||
// Provision your module here, validate config etc. | ||
|
||
if m.Value == 0 { | ||
ctx.Logger().Error("Value must be greater than 0") | ||
return fmt.Errorf("value must be greater than 0") | ||
} | ||
|
||
// Assign the logger to the module for non-request related logging | ||
m.Logger = ctx.Logger() | ||
|
||
return nil | ||
} | ||
|
||
func (m MyModule) Cleanup() error { | ||
// Shutdown your module here, close connections etc. | ||
|
||
return nil | ||
} | ||
|
||
func (m MyModule) OnOriginResponse(response *http.Response, request *http.Request) (*http.Response, error) { | ||
// Return a new response or nil if you want to pass it to the next handler | ||
// If you want to modify the response, return a new response | ||
// If you return an error, the request will be aborted and the response will exit with a 500 status code | ||
|
||
c := app.GetRequestContext(request.Context()) | ||
|
||
// Set a header on the client response | ||
c.ResponseHeader().Set("myHeader", c.GetString("myKey")) | ||
|
||
return nil, nil | ||
} | ||
|
||
func (m MyModule) OnOriginRequest(request *http.Request) { | ||
// Read the request or modify headers here before it is sent to the origin | ||
c := app.GetRequestContext(request.Context()) | ||
|
||
// Use the request logger to log information | ||
c.Logger().Info("Subgraph request", zap.String("host", request.Host)) | ||
} | ||
|
||
func (m MyModule) Middleware(w http.ResponseWriter, r *http.Request, next http.Handler) { | ||
ctx := r.Context() | ||
|
||
c := graphql.GetOperationContext(ctx) | ||
|
||
// Access the GraphQL operation context | ||
fmt.Println( | ||
c.Name, | ||
c.Type, | ||
c.Hash, | ||
c.Content, | ||
) | ||
|
||
// Share a value between different handlers | ||
// In OnOriginResponse we will read this value and set it as response header | ||
appCtx := app.GetRequestContext(ctx) | ||
appCtx.Set("myKey", "myValue") | ||
|
||
// Call the next handler in the chain or return early by calling w.Write() | ||
next.ServeHTTP(w, r) | ||
} | ||
|
||
func (m MyModule) Module() app.ModuleInfo { | ||
return app.ModuleInfo{ | ||
// This is the ID of your module, it must be unique | ||
ID: myModuleID, | ||
New: func() app.Module { | ||
return MyModule{} | ||
}, | ||
} | ||
} | ||
|
||
// Interface guard | ||
var ( | ||
_ app.RouterMiddlewareHandler = (*MyModule)(nil) | ||
_ app.EnginePreOriginHandler = (*MyModule)(nil) | ||
_ app.EnginePostOriginHandler = (*MyModule)(nil) | ||
_ app.Provisioner = (*MyModule)(nil) | ||
_ app.Cleaner = (*MyModule)(nil) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package module | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/wundergraph/cosmo/router/pkg/app" | ||
"github.com/wundergraph/cosmo/router/pkg/config" | ||
"net/http/httptest" | ||
"os" | ||
"testing" | ||
) | ||
|
||
func TestMyModule(t *testing.T) { | ||
|
||
if os.Getenv("MODULE_TESTS") == "" { | ||
t.Skip("Skipping testing in CI environment") | ||
} | ||
|
||
ctx := context.Background() | ||
cfg := config.Config{ | ||
FederatedGraphName: "production", | ||
Modules: map[string]interface{}{ | ||
"myModule": MyModule{ | ||
Value: 1, | ||
}, | ||
}, | ||
} | ||
|
||
routerConfig, err := app.SerializeConfigFromFile("./router-config.json") | ||
assert.Nil(t, err) | ||
|
||
rs, err := app.New( | ||
app.WithFederatedGraphName(cfg.FederatedGraphName), | ||
app.WithStaticRouterConfig(routerConfig), | ||
app.WithModulesConfig(cfg.Modules), | ||
app.WithListenerAddr("http://localhost:3002"), | ||
) | ||
assert.Nil(t, err) | ||
t.Cleanup(func() { | ||
assert.Nil(t, rs.Shutdown(ctx)) | ||
}) | ||
|
||
router, err := rs.NewTestRouter(ctx) | ||
assert.Nil(t, err) | ||
|
||
rr := httptest.NewRecorder() | ||
|
||
var jsonData = []byte(`{ | ||
"query": "query MyQuery { employees { id } }", | ||
"operationName": "MyQuery" | ||
}`) | ||
req := httptest.NewRequest("POST", "/graphql", bytes.NewBuffer(jsonData)) | ||
router.Server.Handler.ServeHTTP(rr, req) | ||
|
||
assert.Equal(t, 200, rr.Code) | ||
|
||
// This header was set by the module | ||
assert.Equal(t, rr.Result().Header.Get("myHeader"), "myValue") | ||
|
||
assert.JSONEq(t, rr.Body.String(), `{"data":{"employees":[{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13}]}}`) | ||
} |
Oops, something went wrong.