- Start Date: 2023-05-17
- RFC Type: feature
- RFC PR: #93 and #103
- RFC Status: approved
- RFC Driver: Manoel Aranda Neto
Add Request and Response bodies to GraphQL errors.
This feature is opt-in by default due to PII concerns.
The Request interface contains information on a HTTP request related to the event.
The Request contains the data field which is the request body. Can be given as string or structural data of any format.
The Response interface contains information on a HTTP response related to the event.
However, the Response interface does not contain the data field which is the response body.
This is necessary to implement the GraphQL Client Errors with syntax highlight.
The Request and Response bodies could contain PII.
Request body example (query language only):
query {
viewer {
login
}
}Response body example:
{
"data": {
"viewer": {
"login": "foo"
}
}
}A Request example with an error (query language only):
query {
viewer {
# note the removed `n` at the end
logi
}
}Response body example:
{
"errors": [
{
"path": [
"query",
"viewer",
"logi"
],
"extensions": {
"code": "undefinedField",
"typeName": "User",
"fieldName": "logi"
},
"locations": [
{
"line": 4,
"column": 5
}
],
"message": "Field 'logi' doesn't exist on type 'User'"
}
]
}Using the locations and the request body (query language only), we can highlight the error in the request body.
query {
viewer {
# note the removed `n` at the end
-> logi
}
}Request body example, full body (not only the query language):
{
"query": "{\n viewer {\n login\n }\n}",
"variables": {}
}The Request body can also contain variables.
{
"query": "{\n viewer {\n login\n }\n}",
"variables": {
"login": "foo"
}
}Because of that, the Request and Response bodies should be sent to Sentry.
See JIRA issues, not disclosing here because they could contain PII.
Related issues and discussions:
Send request body for http client integrations and similar
The proposal is adding a data field in the Response interface and adding an api_target field in the Request interface.
By doing this, we can copy the data scrubbing rules from the Request interface.
When the api_target is graphql, Relay will run data scrubbing in the Response#data field based on the Request#data[variables] field if the query is parameterized, otherwise Relay will run data scrubbing in the Response#data[data] field directly since the most important is Response#data[errors] anyways.
Request example:
{
"request": {
"method": "POST",
"url": "http://absolute.uri/graphql",
"data": {
"foo": "bar"
},
"cookies": "PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;",
"headers": {
"content-type": "text/html"
},
"api_target": "graphql"
}
}api_target: Can be given as string. Values can begraphql,rest, etc.
Response example:
{
"contexts": {
"response": {
"type": "response",
"status_code": 500,
"body_size": 1000,
"data": {
"foo": "bar"
}
}
}
}data: Can be given as string or structural data of any format.
The Response interface keeps arbitrary fields, it is backwards compatible with the current implementation.
The fields Request#data and Response#data could contain PII and they should run data scrubbing aggressively.
Session Replay already sends the request and response bodies, so we can use the same data scrubbing rules.
Since GraphQL is a well defined spec, we can also scrub the GraphQL fields.
Data scrubbing is going to be done on Relay to avoid the data scrubbing rules duplication on every SDK, it's also easier to roll out bug fixes on Relay.
Request example:
{
"query": "{\n viewer {\n login\n }\n}",
"variables": {
"login": "foo"
}
}Response example:
{
"data": {
"viewer": {
"login": "[Filtered]"
}
}
}In this case, we only need to use the Request variables and its keys to scrub the Response data.
Envelopes (Events) contain way lower size limits. The data fields could be large and it could be a problem.
SDKs should discard large and binary bodies by default, using the maxRequestBodySize and maxResponseBodySize (it'll be added) options.
The difference is that for GraphQL errors, this should be enabled by default.
Add a new graphql interface to Contexts.
{
"contexts": {
"graphql": {
"type": "graphql",
"data": "...",
}
}
}We'd need to duplicate or still use some fields from the Request and Response interface.
Size limits would still be a problem.
Add a new envelope item for GraphQL.
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"\n
{"type":"graphql","length":41,"content_type":"application/json"}\n
{"request":"foo","response":"bar"}
This would not be back compatible and must be added to all SDKs.
Add Request and Response bodies as attachments.
{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"\n
{"type":"attachment","length":10,"content_type":"application/json","filename":"request.txt"}\n
foo
{"type":"attachment","length":10,"content_type":"application/json","filename":"response.txt"}\n
bar
Attachments have to be special cased in Sentry, seems hacky, we do that with screenshots already.
- Do we need to send the GraphQL scheme to Sentry in order to do data scrubbing properly?
- Should we send the Request and Response as different envelope items? (avoid the size limit)
- Should PII be scrubbed in the SDK instead?
- The least SDKs have to do is to conform with the Scrubbing Sensitive Data RFC and/or Controlling PII and Credentials in SDKs.