Coprocessor Reference
Property reference
Table of coprocessor request properties.
| Property / Type | Description |
|---|---|
| Control properties | |
| Indicates whether the router should continue processing the current client request. In coprocessor request bodies from the router, this value is always the string value continue.In your coprocessor's response, you can instead return an object with the following format:JSON body you specify.For details, see Terminating a client request. |
| A unique ID corresponding to the client request associated with this coprocessor request.Do not return a different value for this property. If you do, the router treats the coprocessor request as if it failed. |
| A unique ID corresponding to the subgraph request associated with this coprocessor request (only available at the SubgraphRequest and SubgraphResponse stages).Do not return a different value for this property. If you do, the router treats the coprocessor request as if it failed. |
| Indicates which stage of the router's request-handling lifecycle this coprocessor request corresponds to.This value is one of the following:
|
| Indicates which version of the coprocessor request protocol the router is using.Currently, this value is always 1.Do not return a different value for this property. If you do, the router treats the coprocessor request as if it failed. |
| Data properties | |
| The body of the corresponding request or response.This field is populated when the underlying HTTP method is POST. If you are looking for operation data on GET requests, that info will be populated in the path parameter per the GraphQL over HTTP spec.If your coprocessor returns a different value for body, the router replaces the existing body with that value. This is common when terminating a client request.This field's type depends on the coprocessor request's stage:
RouterResponse stage returns redacted errors within the errors field. To process subgraph errors manually in your coprocessor, enable subgraph error inclusion. |
| An object representing the router's shared context for the corresponding client request.If your coprocessor returns a different value for context, the router replaces the existing context with that value. |
| When stage is SupergraphResponse, if present and true then there will be subsequent SupergraphResponse calls to the co-processor for each multi-part (@defer/subscriptions) response. |
| An object mapping of all HTTP header names and values for the corresponding request or response.Ensure headers are handled like HTTP headers in general. For example, normalize header case before your coprocessor operates on them.If your coprocessor returns a different value for headers, the router replaces the existing headers with that value.The router discards any |
| The HTTP method that is used by the request. |
| The RouterService or SupergraphService path that this coprocessor request pertains to. |
| A string representation of the router's current supergraph schema.This value can be very large, so you should avoid including it in coprocessor requests if possible.The router ignores modifications to this value. |
| The name of the subgraph that this coprocessor request pertains to.This value is present only for coprocessor requests from the router's SubgraphService.Do not return a different value for this property. If you do, the router treats the coprocessor request as if it failed. |
| The HTTP status code returned with a response. |
| When stage is SubgraphRequest, this is the full URI of the subgraph the router will query. |
| When stage is ExecutionRequest, this contains the query plan for the client query. It cannot be modified by the coprocessor. |
Context key reference
List of context keys available from the router's request context, which is shared across stages of the processing pipeline.
Core operation
apollo::supergraph::operation_name- Name of the operationapollo::supergraph::operation_kind- Operation kind:query,mutation, orsubscriptionapollo::supergraph::operation_id- Apollo operation IDapollo::supergraph::first_event- First event marker for subscriptions.falseif the current response chunk is not the first response in the stream,noneotherwiseapollo::supergraph_schema_id- Supergraph schema ID
Authentication and authorization
Authentication
apollo::authentication::jwt_claims- Claims extracted from a JWT if present in the requestapollo::authentication::jwt_status- JWT validation status (internal only)
Authorization
apollo::authorization::authentication_required-trueif the operation contains fields marked with@authenticatedapollo::authorization::required_scopes- If the operation contains fields marked with@requiresScopes, it contains the list of scopes usedapollo::authorization::required_policies- If the query contains fields marked with@policy, it contains a map ofpolicy name -> Option<bool>. A coprocessor or Rhai script can edit this map to marktrueon authorization policies that succeed orfalseon ones that fail
Telemetry
Client information
apollo::telemetry::client_name- Client name extracted from the client name headerapollo::telemetry::client_version- Client version extracted from the client version headerapollo::telemetry::client_library_name- Client library nameapollo::telemetry::client_library_version- Client library version
Telemetry control
apollo::telemetry::subgraph_ftv1- JSON-serialized trace data returned by the subgraph when FTV1 is enabledapollo::telemetry::studio_exclude-trueif the current request's trace details should be excluded from Studioapollo::telemetry::contains_graphql_error-trueif the response contains at least one errorapollo::telemetry::counted_errors- Map of already-counted errors (internal)apollo::telemetry::http_request_resend_count_{subgraph_req_id}- HTTP retry count (dynamic key with subgraph request ID suffix)
Demand and cost control
The following keys are populated by the demand control plugin:
apollo::demand_control::estimated_cost- Estimated cost of the requests to be sent to the subgraphsapollo::demand_control::actual_cost- Actual calculated cost of the responses returned by the subgraphsapollo::demand_control::result-COST_OKif allowed, andCOST_TOO_EXPENSIVEif rejected due to cost limitsapollo::demand_control::strategy- Name of the cost calculation strategy used
Caching
Response cache
apollo::response_cache::key- Response cache keyapollo::response_cache::debug_cached_keys- Debug info for cached keysapollo::router::response_cache::cache_info_subgraph_{subgraph_name}- Response cache info per subgraph (dynamic key with subgraph name suffix)
Automatic persisted queries (APQ)
apollo::apq::cache_hit- Present if the request used APQ; true if we got a cache hit for the query ID, false otherwiseapollo::apq::registered-trueif the request registered a query in APQ
Query plan exposure
apollo::expose_query_plan::plan- Contains the query plan serialized as JSON (editing it has no effect on execution)apollo::expose_query_plan::formatted_plan- Query plan formatted as text stringapollo::expose_query_plan::enabled-trueif query plan exposure is enabled
Progressive override
apollo::progressive_override::unresolved_labels- List of unresolved labelsapollo::progressive_override::labels_to_override- List of labels for which overrides are needed
Subscriptions
apollo::subscriptions::fatal_error- Fatal subscription error flag
Persisted queries
apollo_persisted_queries::client_name- Client name for PQ operationsapollo_persisted_queries::safelist::skip_enforcement- Skip safelist enforcement
Connectors
apollo_connectors::sources_in_query_plan- List of connector sources in query plan
Example requests by stage
RouterRequest
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "RouterRequest",
5 "control": "continue",
6 "id": "1b19c05fdafc521016df33148ad63c1b",
7
8 // Data properties
9 "headers": {
10 "cookie": [
11 "tasty_cookie=strawberry"
12 ],
13 "content-type": [
14 "application/json"
15 ],
16 "host": [
17 "127.0.0.1:4000"
18 ],
19 "apollo-federation-include-trace": [
20 "ftv1"
21 ],
22 "apollographql-client-name": [
23 "manual"
24 ],
25 "accept": [
26 "*/*"
27 ],
28 "user-agent": [
29 "curl/7.79.1"
30 ],
31 "content-length": [
32 "46"
33 ]
34 },
35 "body": "{
36 \"query\": \"query GetActiveUser {\n me {\n name\n}\n}\"
37 }",
38 "context": {
39 "entries": {
40 "accepts-json": false,
41 "accepts-wildcard": true,
42 "accepts-multipart": false
43 }
44 },
45 "sdl": "...", // String omitted due to length
46 "path": "/",
47 "method": "POST"
48}RouterResponse
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "RouterResponse",
5 "control": "continue",
6 "id": "1b19c05fdafc521016df33148ad63c1b",
7
8 // Data properties
9 "headers": {
10 "vary": [
11 "origin"
12 ],
13 "content-type": [
14 "application/json"
15 ]
16 },
17 "body": "{
18 \"data\": {
19 \"me\": {
20 \"name\": \"Ada Lovelace\"
21 }
22 }
23 }",
24 "context": {
25 "entries": {
26 "apollo_telemetry::subgraph_metrics_attributes": {},
27 "accepts-json": false,
28 "accepts-multipart": false,
29 "apollo::telemetry::client_name": "manual",
30 "apollo_telemetry::usage_reporting": {
31 "statsReportKey": "# Long\nquery Long{me{name}}",
32 "referencedFieldsByType": {
33 "User": {
34 "fieldNames": [
35 "name"
36 ],
37 "isInterface": false
38 },
39 "Query": {
40 "fieldNames": [
41 "me"
42 ],
43 "isInterface": false
44 }
45 }
46 },
47 "apollo::telemetry::client_version": "",
48 "accepts-wildcard": true
49 }
50 },
51 "statusCode": 200,
52 "sdl": "..." // Omitted due to length
53}SupergraphRequest
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "SupergraphRequest",
5 "control": "continue",
6
7 // Data properties
8 "headers": {
9 "cookie": ["tasty_cookie=strawberry"],
10 "content-type": ["application/json"],
11 "host": ["127.0.0.1:4000"],
12 "apollo-federation-include-trace": ["ftv1"],
13 "apollographql-client-name": ["manual"],
14 "accept": ["*/*"],
15 "user-agent": ["curl/7.79.1"],
16 "content-length": ["46"]
17 },
18 "body": {
19 "query": "query Long {\n me {\n name\n}\n}",
20 "operationName": "MyQuery",
21 "variables": {}
22 },
23 "context": {
24 "entries": {
25 "accepts-json": false,
26 "accepts-wildcard": true,
27 "accepts-multipart": false,
28 "this-is-a-test-context": 42
29 }
30 },
31 "serviceName": "service name shouldn't change",
32 "uri": "http://thisurihaschanged"
33}SupergraphResponse
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "SupergraphResponse",
5 "control": {
6 "break": 200
7 },
8
9 // Data properties
10 "body": {
11 "errors": [{ "message": "my error message" }]
12 },
13 "context": {
14 "entries": {
15 "testKey": true
16 }
17 },
18 "headers": {
19 "aheader": ["a value"]
20 }
21}ExecutionRequest
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "ExecutionRequest",
5 "control": "continue",
6
7 // Data properties
8 "headers": {
9 "cookie": ["tasty_cookie=strawberry"],
10 "content-type": ["application/json"],
11 "host": ["127.0.0.1:4000"],
12 "apollo-federation-include-trace": ["ftv1"],
13 "apollographql-client-name": ["manual"],
14 "accept": ["*/*"],
15 "user-agent": ["curl/7.79.1"],
16 "content-length": ["46"]
17 },
18 "body": {
19 "query": "query Long {\n me {\n name\n}\n}",
20 "operationName": "MyQuery"
21 },
22 "context": {
23 "entries": {
24 "accepts-json": false,
25 "accepts-wildcard": true,
26 "accepts-multipart": false,
27 "this-is-a-test-context": 42
28 }
29 },
30 "serviceName": "service name shouldn't change",
31 "uri": "http://thisurihaschanged",
32 "queryPlan": {
33 "usage_reporting": {
34 "statsReportKey": "# Me\nquery Me{me{name username}}",
35 "referencedFieldsByType": {
36 "User": { "fieldNames": ["name", "username"], "isInterface": false },
37 "Query": { "fieldNames": ["me"], "isInterface": false }
38 }
39 },
40 "root": {
41 "kind": "Fetch",
42 "serviceName": "accounts",
43 "variableUsages": [],
44 "operation": "query Me__accounts__0{me{name username}}",
45 "operationName": "Me__accounts__0",
46 "operationKind": "query",
47 "id": null,
48 "inputRewrites": null,
49 "outputRewrites": null,
50 "authorization": {
51 "is_authenticated": false,
52 "scopes": [],
53 "policies": []
54 }
55 },
56 "formatted_query_plan": "QueryPlan {\n Fetch(service: \"accounts\") {\n {\n me {\n name\n username\n }\n }\n },\n}",
57 "query": {
58 "string": "query Me {\n me {\n name\n username\n }\n}\n",
59 "fragments": { "map": {} },
60 "operations": [
61 {
62 "name": "Me",
63 "kind": "query",
64 "type_name": "Query",
65 "selection_set": [
66 {
67 "Field": {
68 "name": "me",
69 "alias": null,
70 "selection_set": [
71 {
72 "Field": {
73 "name": "name",
74 "alias": null,
75 "selection_set": null,
76 "field_type": { "Named": "String" },
77 "include_skip": { "include": "Yes", "skip": "No" }
78 }
79 },
80 {
81 "Field": {
82 "name": "username",
83 "alias": null,
84 "selection_set": null,
85 "field_type": { "Named": "String" },
86 "include_skip": { "include": "Yes", "skip": "No" }
87 }
88 }
89 ],
90 "field_type": { "Named": "User" },
91 "include_skip": { "include": "Yes", "skip": "No" }
92 }
93 }
94 ],
95 "variables": {}
96 }
97 ],
98 "subselections": {},
99 "unauthorized": {
100 "paths": [],
101 "errors": { "log": true, "response": "errors" }
102 },
103 "filtered_query": null,
104 "defer_stats": {
105 "has_defer": false,
106 "has_unconditional_defer": false,
107 "conditional_defer_variable_names": []
108 },
109 "is_original": true
110 }
111 }
112}ExecutionResponse
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "ExecutionResponse",
5 "control": {
6 "break": 200
7 },
8
9 // Data properties
10 "body": {
11 "errors": [{ "message": "my error message" }]
12 },
13 "context": {
14 "entries": {
15 "testKey": true
16 }
17 },
18 "headers": {
19 "aheader": ["a value"]
20 }
21}SubgraphRequest
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "SubgraphRequest",
5 "control": "continue",
6 "id": "666d677225c1bc6d7c54a52b409dbd4e",
7 "subgraphRequestId": "b5964998b2394b64a864ef802fb5a4b3",
8
9 // Data properties
10 "headers": {},
11 "body": {
12 "query": "query TopProducts__reviews__1($representations:[_Any!]!){_entities(representations:$representations){...on Product{reviews{body id}}}}",
13 "operationName": "TopProducts__reviews__1",
14 "variables": {
15 "representations": [
16 {
17 "__typename": "Product",
18 "upc": "1"
19 },
20 {
21 "__typename": "Product",
22 "upc": "2"
23 },
24 {
25 "__typename": "Product",
26 "upc": "3"
27 }
28 ]
29 }
30 },
31 "context": {
32 "entries": {
33 "apollo_telemetry::usage_reporting": {
34 "statsReportKey": "# TopProducts\nquery TopProducts{topProducts{name price reviews{body id}}}",
35 "referencedFieldsByType": {
36 "Query": {
37 "fieldNames": ["topProducts"],
38 "isInterface": false
39 },
40 "Review": {
41 "fieldNames": ["body", "id"],
42 "isInterface": false
43 },
44 "Product": {
45 "fieldNames": ["price", "name", "reviews"],
46 "isInterface": false
47 }
48 }
49 },
50 "apollo::telemetry::client_version": "",
51 "apollo_telemetry::subgraph_metrics_attributes": {},
52 "apollo::telemetry::client_name": ""
53 }
54 },
55 "uri": "https://reviews.demo.starstuff.dev/",
56 "method": "POST",
57 "serviceName": "reviews"
58}SubgraphResponse
Click to expand
1{
2 // Control properties
3 "version": 1,
4 "stage": "SubgraphResponse",
5 "id": "b7810c6f7f95640fd6c6c8781e3953c0",
6 "subgraphRequestId": "b5964998b2394b64a864ef802fb5a4b3",
7 "control": "continue",
8
9 // Data properties
10 "headers": {
11 "etag": ["W/\"d3-7aayASjs0+e2c/TpiAYgEu/yyo0\""],
12 "via": ["2 fly.io"],
13 "server": ["Fly/90d459b3 (2023-03-07)"],
14 "date": ["Thu, 09 Mar 2023 14:28:46 GMT"],
15 "x-powered-by": ["Express"],
16 "x-ratelimit-limit": ["10000000"],
17 "access-control-allow-origin": ["*"],
18 "x-ratelimit-remaining": ["9999478"],
19 "content-type": ["application/json; charset=utf-8"],
20 "fly-request-id": ["01GV3CCG5EM3ZNVZD2GH0B00E2-lhr"],
21 "x-ratelimit-reset": ["1678374007"]
22 },
23 "body": {
24 "data": {
25 "_entities": [
26 {
27 "reviews": [
28 {
29 "body": "Love it!",
30 "id": "1"
31 },
32 {
33 "body": "Prefer something else.",
34 "id": "4"
35 }
36 ]
37 },
38 {
39 "reviews": [
40 {
41 "body": "Too expensive.",
42 "id": "2"
43 }
44 ]
45 },
46 {
47 "reviews": [
48 {
49 "body": "Could be better.",
50 "id": "3"
51 }
52 ]
53 }
54 ]
55 }
56 },
57 "context": {
58 "entries": {
59 "apollo_telemetry::usage_reporting": {
60 "statsReportKey": "# TopProducts\nquery TopProducts{topProducts{name price reviews{body id}}}",
61 "referencedFieldsByType": {
62 "Product": {
63 "fieldNames": ["price", "name", "reviews"],
64 "isInterface": false
65 },
66 "Query": {
67 "fieldNames": ["topProducts"],
68 "isInterface": false
69 },
70 "Review": {
71 "fieldNames": ["body", "id"],
72 "isInterface": false
73 }
74 }
75 },
76 "apollo::telemetry::client_version": "",
77 "apollo_telemetry::subgraph_metrics_attributes": {},
78 "apollo::telemetry::client_name": ""
79 }
80 },
81 "serviceName": "reviews",
82 "statusCode": 200
83}