Search code examples
node.jsgraphqlapolloapollo-server

Getting complete query string from inside of resolver


I'm new to nodejs and apollo server, so don't judge me.

Problem sounds exactly same as title: "how to get graphql string inside resolver function?".

Actually, you have four args in every resolver: parent, args, context, info. Some info here: https://www.apollographql.com/docs/apollo-server/essentials/data#type-signature

I made my mind to write function, that gathers nested object inside context to regenerate query string. Why I need it? Good question. I'm writing microservice, so when i got nested query to field which is outside from current microservice I pass query by http.

My resolver:

eventByID: async (root, args, context) => {
    const event = await EventModel.findById(root.id);
    event.creator = await nestedContextProvider(context, 'creator', event.creator);
    return eventFascade(event); //just facade for object - nothing serious
},    

It refers to nestedContextProvider for solving nested context:

const nestedQueryTraverser = (nestedQueryArray) => {
    const nestedQueryTraversed = nestedQueryArray.selectionSet.selections.map(element => (
    element.selectionSet === undefined
      ? element.name.value
      : `${element.name.value}{${nestedQueryTraverser(element)}}`));
    return nestedQueryTraversed;
};

const nestedContextProvider = async (context, checkField, ID) => {
    if (context.operation.selectionSet.selections[0].selectionSet.selections
    .find(selector => selector.name.value === checkField)) {
    let nestedFieldsArr = context.operation.selectionSet.selections[0]
      .selectionSet.selections.find(selector => selector.name.value === checkField);
    nestedFieldsArr = nestedQueryTraverser(nestedFieldsArr);
    const a = (await users(ID, nestedFieldsArr));
    return a.data.usersByIDs[0];
    }
    return ID;
};

So it works for me, but I know there must be better solution.

Any ideas?


Solution

  • The graphql package includes a print function that takes any AST and returns the string representation, so you can do something like this:

    const { print } = require('graphql')
    
    function anyResolver (parent, args, context, info) {
      const operationString = print(info.operation)
      // Fragments are not included in the operation, but we still need to print
      // them otherwise our document will reference non-existing fragments
      const fragmentsString = Object.keys(info.fragments)
        .map(fragmentName => print(info.fragments[fragmentName]))
        .join('\n\n')
      const documentString = `${operationString}\n\n${fragmentsString}`
    }