Skip to content

Use the Cloudflare GraphQL API to gather data about your GraphQL API’s current usage and configure Cloudflare’s GraphQL malicious query protection to log or block malicious queries.

Introduction

Query size is defined as the number of terminal fields (leaves) in the query, whereas query depth is the deepest level at which a leaf is present. For example, the size of this query will be reported as 4 (terminalField[1-4] all contribute to this counter), and the depth will be reported as 3 (terminalField3 and terminalField4 are at depth level 3).

GraphQL query
{
terminalField1
nonTerminalField1(filter: 123) {
terminalField2
nonTerminalField2 {
terminalField3
terminalField4
}
}
}

Gather GraphQL statistics

Using the new apiGatewayGraphqlQueryAnalyticsGroups node in the Cloudflare GraphQL API, you can retrieve apiGatewayGraphqlQuerySize and apiGatewayGraphqlQueryDepth dimensions.

GraphQL query
query ApiGatewayGraphqlQueryAnalytics(
$zoneTag: string
$start: Time
$end: Time
) {
viewer {
zones(filter: { zoneTag: $zoneTag }) {
apiGatewayGraphqlQueryAnalyticsGroups(
limit: 100
orderBy: [
apiGatewayGraphqlQuerySize_DESC
apiGatewayGraphqlQueryDepth_DESC
]
filter: { datetime_geq: $start, datetime_leq: $end }
) {
count
dimensions {
apiGatewayGraphqlQuerySize
apiGatewayGraphqlQueryDepth
}
}
}
}
}

With the above query, you will get the following response:

Response
{
"data": {
"viewer": {
"zones": [
{
"apiGatewayGraphqlQueryAnalyticsGroups": [
{
"count": 10,
"dimensions": {
"apiGatewayGraphqlQueryDepth": 1,
"apiGatewayGraphqlQuerySize": 11
}
},
{
"count": 10,
"dimensions": {
"apiGatewayGraphqlQueryDepth": 1,
"apiGatewayGraphqlQuerySize": 2
}
}
]
}
]
}
},
"errors": null
}

In the response example, Cloudflare observed 10 requests with depth 1 and size 11, and 10 requests with depth 1 and size 2 in the selected timeframe.

Analyze GraphQL statistics

You can use the response to compute percentiles across the attributes and set a threshold on what is allowed. For example, you can use a simple heuristic like 1.5 * p99 for query size or depth.

Here is a simple Python script that will report query size and depth p-levels given the GraphQL API response output above (as a JSON file):

Python script
#!/usr/bin/env python3
import json
import numpy as np
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--response", help="Path to the API JSON response file with the apiGatewayGraphqlQueryAnalyticsGroups node", required=True)
args = parser.parse_args()
with open(args.response) as f:
query_sizes = np.array([], dtype=np.uint16)
query_depths = np.array([], dtype=np.uint8)
data = json.load(f)['data']['viewer']['zones'][0]['apiGatewayGraphqlQueryAnalyticsGroups']
for datapoint in data:
query_sizes = np.append(query_sizes, [datapoint['dimensions']['apiGatewayGraphqlQuerySize']] * datapoint['count'])
query_depths = np.append(query_depths, [datapoint['dimensions']['apiGatewayGraphqlQueryDepth']] * datapoint['count'])
quantiles = [0.99,