The code in this repository is experimental and has been provided for reference purposes only. Community feedback is welcome but this project may not be supported in the same way that repositories in the official Apollo GraphQL GitHub organization are. If you need help you can file an issue on this repository, contact Apollo to talk to an expert, or create a ticket directly in Apollo Studio.
This repo demonstrates running both @apollo/gateway
and Apollo Router, and using the gateway Node.js server to conditionally proxy traffic to the router to support a gradual release strategy. It uses Unleash to demonstrate a somewhat-realistic feature toggle system.
-
Clone this repository
git clone https://github.com/apollosolutions/router-node-proxy
-
Build and run the services:
docker compose up --build
-
Create the feature toggles:
- The rollout feature toggle:
curl --location --request POST 'http://localhost:4242/api/admin/projects/default/features' \ --header 'Authorization: *:*.unleash-insecure-api-token' \ --header 'Content-Type: application/json' \ --data-raw '{ "type": "release", "name": "router-rollout", "description": "", "impressionData": false }'
- The replay-on-error feature toggle:
curl --location --request POST 'http://localhost:4242/api/admin/projects/default/features' \ --header 'Authorization: *:*.unleash-insecure-api-token' \ --header 'Content-Type: application/json' \ --data-raw '{ "type": "release", "name": "router-replay-on-error", "description": "", "impressionData": false }'
- The rollout feature toggle:
-
Restart the services with
<ctrl-c>
anddocker compose up
. -
Visit http://localhost:4000. Execute an operation:
query Query { me { id } }
-
Observe
Handling the request in Node.js
log messages. -
Add a override header to send the request to the router:
x-use-router: true
and execute the operation. -
Observe
Forwarding request to the router
log messages. -
Rollout out the router to 50% of requests:
curl --location --request POST 'http://localhost:4242/api/admin/projects/default/features/router-rollout/environments/development/strategies' \ --header 'Authorization: *:*.unleash-insecure-api-token' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "flexibleRollout", "constraints": [], "parameters": { "rollout": "50", "stickiness": "random", "groupId": "router-rollout" } }'
-
Enable the feature toggle:
curl --location --request POST 'http://localhost:4242/api/admin/projects/default/features/router-rollout/environments/development/on' \ --header 'Authorization: *:*.unleash-insecure-api-token'
-
Disable the
x-use-router
header and execute the request several times. -
Observe that about 50% of requests print
Forwarding request to the router
to the logs. -
Enable the replay-on-error feature toggle:
curl --location --request POST 'http://localhost:4242/api/admin/projects/default/features/router-replay-on-error/environments/development/on' \ --header 'Authorization: *:*.unleash-insecure-api-token'
-
Execute an operation that will trigger an error:
query Query { me { foo } }
-
Observe three log messages indicating that the Node.js server replayed the request in the gateway:
Forwarding request to the router ROUTER PROXY ERROR: [{"message":"cannot query field 'foo' on type 'User'"}] Replaying the request in Node.js
-
Set the router rollout feature toggle to 100%. You can also log into the Unleash UI by navigating to http://localhost:4242/, logging in with username
admin
and passwordunleash4all
and editing the existing rollout strategy.curl --location --request POST 'http://localhost:4242/api/admin/projects/default/features/router-rollout/environments/development/strategies' \ --header 'Authorization: *:*.unleash-insecure-api-token' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "flexibleRollout", "constraints": [], "parameters": { "rollout": "100", "stickiness": "random", "groupId": "router-rollout" } }'
-
Disable router replay-on-error:
curl --location --request POST 'http://localhost:4242/api/admin/projects/default/features/router-replay-on-error/environments/development/off' \ --header 'Authorization: *:*.unleash-insecure-api-token'
-
Try a router-specific feature like
@defer
:query Query { me { id } ... @defer { topProducts { name } } }
- The "replay-on-error" functionality can't handle chunked responses, so it's incompatible with
@defer
.