DauleDK
DauleDK

Reputation: 3433

Apollo nodejs server; How to get mutation/query schema path in the request context when writing a plugin?

I'm writing an Apollo server plugin for node.js, and my goal is to improve my teams debugging experience. My plugin currently looks something like this:

export function eddyApolloPlugin(): ApolloServerPlugin {
    return {
        requestDidStart(requestContext) {
            // Set requestId on the header
            const requestId = (requestContext?.context as EddyContext)?.requestId;
            if (requestId) {
                requestContext.response?.http?.headers.set('requestId', requestId);
            }
            return {
                willSendResponse(context) { // <== Where do I find the "path" in the schema here?
                    // Inspired by this: https://blog.sentry.io/2020/07/22/handling-graphql-errors-using-sentry
                    // and the official documentation here: https://docs.sentry.io/platforms/node/
                    // handle all errors
                    for (const error of requestContext?.errors || []) {
                        handleError(error, context);
                    }
                },
            };
        },
    };
}

I would like to know if I can access the path in the schema here? It's pretty easy to find the name of mutaiton/query with operation.operationName, but where can I get the name of the query/mutation as defined in the schema?

Solution

export function eddyApolloPlugin(): ApolloServerPlugin {
    return {
        requestDidStart(requestContext) {
            // Set requestId on the header
            const requestId = (requestContext?.context as EddyContext)?.requestId;
            if (requestId) {
                requestContext.response?.http?.headers.set('requestId', requestId);
            }
            return {
                didResolveOperation(context) {
                    const operationDefinition = context.document
                        .definitions[0] as OperationDefinitionNode;
                    const fieldNode = operationDefinition?.selectionSet
                        .selections[0] as FieldNode;
                    const queryName = fieldNode?.name?.value;
                    // queryName is what I was looking for!
                },
            };
        },
    };
}

Upvotes: 1

Views: 1812

Answers (1)

Lin Du
Lin Du

Reputation: 102237

Your requirement is not very clear. If you want to get the name of the query/mutation to distinguish which query or mutation the client sends.

You could get the name from context.response.data in willSendResponse event handler.

E.g.

server.ts:

import { ApolloServer, gql } from 'apollo-server';
import { ApolloServerPlugin } from 'apollo-server-plugin-base';
import { parse, OperationDefinitionNode, FieldNode } from 'graphql';

function eddyApolloPlugin(): ApolloServerPlugin {
  return {
    requestDidStart(requestContext) {
      return {
        didResolveOperation(context) {
          console.log('didResolveOperation');
          const obj = parse(context.request.query!);
          const operationDefinition = obj.definitions[0] as OperationDefinitionNode;
          const selection = operationDefinition.selectionSet.selections[0] as FieldNode;
          console.log('operationName: ', context.request.operationName);
          console.log(`${context.operation!.operation} name:`, selection.name.value);
        },
        willSendResponse(context) {
          console.log('willSendResponse');
          console.log('operationName: ', context.request.operationName);
          console.log(`${context.operation!.operation} name:`, Object.keys(context.response.data!)[0]);
        },
      };
    },
  };
}

const typeDefs = gql`
  type Query {
    hello: String
  }
  type Mutation {
    update: String
  }
`;
const resolvers = {
  Query: {
    hello() {
      return 'Hello, World!';
    },
  },
  Mutation: {
    update() {
      return 'success';
    },
  },
};

const server = new ApolloServer({ typeDefs, resolvers, plugins: [eddyApolloPlugin()] });
const port = 3000;
server.listen(port).then(({ url }) => console.log(`Server is ready at ${url}`));

GraphQL Query:

query test {
  hello
}

the logs of the server:

didResolveOperation
operationName:  test
query name: hello
willSendResponse
operationName:  test
query name: hello

GraphQL Mutation:

mutation test {
  update
}

the logs of the server:

didResolveOperation
operationName:  test
mutation name: update
willSendResponse
operationName:  test
mutation name: update

Upvotes: 2

Related Questions