Webpack GraphQL loader should augment graphql-tag loader with filename and include this as a request header
Spun out of #331697 (closed).
As part of the GraphQL observability improvements, it would be very helpful to have a way of easily identifying a GraphQL request from GitLab client.
An approach to doing this which doesn't require a lot of changes to the existing GraphQL queries, and would not require developers to follow a specific pattern when creating new queries would be preferable, and this issue describes such an approach.
Proposal: include the query file in an HTTP header
Chain the GraphQL webpack loader, adding meta-information to the GraphQL AST
Webpack supports loader chaining: https://webpack.js.org/contribute/writing-a-loader/#chaining
Take advantage of the fact that loaders can be chained together. Instead of writing a single loader that tackles five tasks, write five simpler loaders that divide this effort. Isolating them not only keeps each individual loader simple, but may allow for them to be used for something you hadn't thought of originally.
We use this to chain an additional loader onto the GraphQL loading process:
This is the current graphql
loader configuration:
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
},
We add an additional loader to the chain:
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: ['graphql-tag/loader', path.resolve('path/to/lib/graphql-metadata-loader')],
},
The graphql-metadata-loader
"wraps" the output from graphql-tag/loader
and appends something along the following lines:
module.exports.meta = { querySource: '<path/to/graphql/query>.graphql' };
Inject the header via an Apollo Middleware
We build a small GraphQL middleware, similar to some of the examples from https://www.apollographql.com/docs/react/networking/advanced-http-networking.
- We inject a middleware into our Apollo client stack.
- This middleware checks the operation for the existence of the
meta.querySource
attribute on the query or mutation. - If it exists, it injects it via a header, eg
X-GitLab-GraphQL-Query-Source: app/assets/javascripts/alerts_settings/graphql/queries/get_current_integration.query.graphql
Benefits
On the server-side, we log the X-GitLab-GraphQL-Query-Source
header in the logs for GraphQL queries. We are then able to use this header for attribution, as an aggregation key, etc.
This approach does not require boilerplate for each query, or GraphQL request, making it simple to implement.