Configure GraphQL Proxying
API7 Gateway can proxy GraphQL traffic like any other HTTP API. In environments where the GraphQL-aware plugins are available, you can also apply GraphQL-specific rate limiting and caching policies.
Prerequisites
- An API7 Enterprise instance is running.
- A Gateway Group is created and a Gateway instance is running.
- A token from the Dashboard.
Proxy GraphQL Requests
Start with a standard HTTP route that forwards GraphQL requests to the upstream.
The following examples use https://countries.trevorblades.com/ as an upstream. When proxying to an HTTPS upstream that expects its own hostname, set scheme: https and pass_host: node.
- ADC
- Admin API
services:
- name: graphql-service
upstream:
scheme: https
pass_host: node
nodes:
- host: countries.trevorblades.com
port: 443
weight: 1
routes:
- name: graphql-route
uris:
- /graphql
methods:
- POST
labels:
docs-example: graphql-service
Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=graphql-service
Synchronize the reviewed configuration:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=graphql-service
# 1. Create a Service for the GraphQL upstream
curl -k "https://localhost:7443/apisix/admin/services/graphql-service?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "graphql-service",
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": [
{
"host": "countries.trevorblades.com",
"port": 443,
"weight": 1
}
]
}
}'
# 2. Create a Route for the Service
curl -k "https://localhost:7443/apisix/admin/routes/graphql-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "graphql-route",
"paths": ["/graphql"],
"methods": ["POST"],
"service_id": "graphql-service"
}'
In the local validation environment, the basic Admin API example worked end to end after configuring the upstream with scheme: https and pass_host: node.
The following scenarios update this same service and route. Verify rate limiting before applying the caching scenario because the caching configuration replaces graphql-limit-count with graphql-proxy-cache.
GraphQL Rate Limiting
The graphql-limit-count plugin provides GraphQL-aware rate limiting based on query depth.
Configure GraphQL Rate Limiting
Update the existing route to enable the graphql-limit-count plugin. This plugin only supports the POST method.
This plugin requires additional fields beyond count, time_window, key_type, and key. At minimum, include policy. For example, the local policy uses policy: local.
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/routes/graphql-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "graphql-route",
"paths": ["/graphql"],
"service_id": "graphql-service",
"methods": ["POST"],
"plugins": {
"graphql-limit-count": {
"count": 6,
"time_window": 60,
"rejected_code": 429,
"policy": "local",
"key_type": "var",
"key": "remote_addr"
}
}
}'
services:
- name: graphql-service
upstream:
scheme: https
pass_host: node
nodes:
- host: countries.trevorblades.com
port: 443
weight: 1
routes:
- name: graphql-route
uris:
- /graphql
methods:
- POST
plugins:
graphql-limit-count:
count: 6
time_window: 60
rejected_code: 429
policy: local
key_type: var
key: remote_addr
labels:
docs-example: graphql-service
Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=graphql-service
Synchronize the reviewed configuration:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=graphql-service
Repeat the following query four times. The first three requests should succeed and the fourth should return 429 Too Many Requests:
for i in $(seq 1 4); do
curl -s -o /dev/null -w '%{http_code}\n' "http://localhost:9080/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"query { continents { code } }"}'
done
GraphQL Caching
The graphql-proxy-cache plugin provides GraphQL-aware caching for query operations while bypassing mutations.
Configure GraphQL Caching
Update the same route to replace the rate-limiting configuration with graphql-proxy-cache.
In the local validation environment, each GraphQL-aware plugin configuration was validated independently. graphql-limit-count returned 429 after the configured quota was exceeded, and graphql-proxy-cache returned Apisix-Cache-Status: MISS on the first request and Apisix-Cache-Status: HIT on the second identical request.
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/routes/graphql-route?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "graphql-route",
"paths": ["/graphql"],
"service_id": "graphql-service",
"methods": ["POST"],
"plugins": {
"graphql-proxy-cache": {}
}
}'
services:
- name: graphql-service
upstream:
scheme: https
pass_host: node
nodes:
- host: countries.trevorblades.com
port: 443
weight: 1
routes:
- name: graphql-route
uris:
- /graphql
methods:
- POST
plugins:
graphql-proxy-cache: {}
labels:
docs-example: graphql-service
Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=graphql-service
Synchronize the reviewed configuration:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=graphql-service
Purge Cache
You can purge the cache for a specific GraphQL query by sending a DELETE request to the plugin's control endpoint.
curl -X DELETE "http://localhost:9080/apisix/plugin/graphql-proxy-cache/*"
Validate the Configuration
You can test the basic GraphQL proxying by sending a POST request with a GraphQL query.
curl -X POST "http://localhost:9080/graphql" \
-H "Content-Type: application/json" \
-d '{"query": "query { countries { code } }"}'
The gateway proxies the GraphQL request and returns the response from the upstream:
{"data":{"countries":[{"code":"AD"},{"code":"AE"}]}}
If graphql-proxy-cache is enabled, repeat the same query twice and confirm the cache status headers:
curl -i -X POST "http://localhost:9080/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"query { continents { code } }"}'
curl -i -X POST "http://localhost:9080/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"query { continents { code } }"}'
The first response should include Apisix-Cache-Status: MISS and the second should include Apisix-Cache-Status: HIT.
Next Steps
- Configure Rate Limiting — explore more advanced rate limiting strategies.
- Configure Proxy Caching — learn about standard HTTP caching.
- Configure gRPC Proxying — handle gRPC services and transcoding.
- Configure WebSocket Proxying — manage real-time, bidirectional communication.