Graphql-tools: Aliases do not work with default resolvers in merged schemas

Created on 5 Oct 2018  Â·  5Comments  Â·  Source: ardatan/graphql-tools

See https://github.com/apollographql/apollo-server/issues/1724 for all the background on this, I was told this is probably an issue with graphql-tools itself, not apollo-server.


Comment by Dan https://github.com/apollographql/apollo-server/issues/1724#issuecomment-425596109

This issues doesn't seem to be related to fragments. Aliases do not appear to be working with default resolvers in merged schemas:


Given this query:

# Write your query or mutation here
{
  book {
    cat: category
  }
}

With this code (reproduction): https://glitch.com/edit/#!/pinto-hip

const { ApolloServer, gql, makeExecutableSchema, mergeSchemas } = require('apollo-server');

const typeDefs = gql`
    type Query {
      book: Book
    }
    type Book {
      category: String!
    }
  `;

  const schema = makeExecutableSchema({ typeDefs });

  const resolvers = {
    Query: {
      book: () => ({ category: 'Test' })
    }
  };

  const server = new ApolloServer({
    schema: mergeSchemas({
      schemas: [ schema ],
      resolvers
    }),
  });



server.listen()
  .then(console.log)
  .catch(console.log);

GQL throws an error:

{
  "data": {
    "book": null
  },
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Book.category.",
      "locations": [
        {
          "line": 3,
          "column": 5
        }
      ],
      "path": [
        "book",
        "cat"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "Error: Cannot return null for non-nullable field Book.category.",
            "    at completeValue (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:568:13)",
            "    at completeValueCatchingError (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:503:19)",
            "    at resolveField (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:447:10)",
            "    at executeFields (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:293:18)",
            "    at collectAndExecuteSubfields (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:717:10)",
            "    at completeObjectValue (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:707:10)",
            "    at completeValue (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:598:12)",
            "    at completeValueCatchingError (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:503:19)",
            "    at resolveField (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:447:10)",
            "    at executeFields (/rbd/pnpm-volume/0897a123-e913-41b8-a689-0921f96aa33a/node_modules/.registry.npmjs.org/graphql/14.0.2/node_modules/graphql/execution/execute.js:293:18)"
          ]
        }
      }
    }
  ]
}
blocking bug has-reproduction

Most helpful comment

There is a problem with the above example, see this repository for corrected example.

const { ApolloServer, gql } = require('apollo-server');
const { makeExecutableSchema, mergeSchemas } = require('graphql-tools');

const typeDefs = gql`
    type Query {
      book: Book
    }
    type Book {
      category: String!
    }
  `;

  const resolvers = {
    Query: {
      book: () => ({ category: 'Test' })
    }
  };

  const schema = makeExecutableSchema({
    typeDefs,
    resolvers,   //     <=== this is the change, the resolver has to be passed to the subschema, not the gateway
  });

  const server = new ApolloServer({
    schema: mergeSchemas({
      schemas: [ schema ],
    }),
  });

server.listen()
  .then(console.log)
  .catch(console.log);

Works with this query:

# Write your query or mutation here
{
  book {
    cat: category
  }
}

Gives this result:

{
  "data": {
    "book": {
      "cat": "Test"
    }
  }
}

You can pass resolvers to mergeSchemas/stitchSchemas, too, but those resolvers are for your new fields and do not require any special alias support. The initial version has the effect of overriding the special stitching resolver (defaultMergedResolver) to disable aliasing support.

All 5 comments

Currently, the workarounds are:

1) Do not use aliases

2) Map default resolvers for all fields you will alias:

import { keyBy, mapValues } from "lodash";

const monkeyPatchForAliases = (...props) =>
  mapValues(
    keyBy(props.map(prop => ({ prop, fn: parent => parent[prop] })), "prop"),
    obj => obj.fn
  );

const resolvers = {
    Query: {
      book: () => ({ category: 'Test' })
    },
    Book: monkeyPatchForAliases("category")
  };

Thanks for fixing the issue. It's working in v4.0.8 but unfortunately there is a regression in v5.0.0.

There is a problem with the above example, see this repository for corrected example.

const { ApolloServer, gql } = require('apollo-server');
const { makeExecutableSchema, mergeSchemas } = require('graphql-tools');

const typeDefs = gql`
    type Query {
      book: Book
    }
    type Book {
      category: String!
    }
  `;

  const resolvers = {
    Query: {
      book: () => ({ category: 'Test' })
    }
  };

  const schema = makeExecutableSchema({
    typeDefs,
    resolvers,   //     <=== this is the change, the resolver has to be passed to the subschema, not the gateway
  });

  const server = new ApolloServer({
    schema: mergeSchemas({
      schemas: [ schema ],
    }),
  });

server.listen()
  .then(console.log)
  .catch(console.log);

Works with this query:

# Write your query or mutation here
{
  book {
    cat: category
  }
}

Gives this result:

{
  "data": {
    "book": {
      "cat": "Test"
    }
  }
}

You can pass resolvers to mergeSchemas/stitchSchemas, too, but those resolvers are for your new fields and do not require any special alias support. The initial version has the effect of overriding the special stitching resolver (defaultMergedResolver) to disable aliasing support.

Please let us know, however, if you have discovered divergent behavior from graphql-tools v4.0.8 and v5.0.0.

I got them both to error with the incorrect setup and work correctly with the repository I linked, but you may be referring to a different query/code sample -- if something seems not right, please go right on ahead and open a new issue.

Please include as minimal of a reproduction as possible to facilitate a fix!

Thanks!

Thanks @yaacovCR . I tried to reproduce the issue with sample code here but it's working as expected.

Was this page helpful?
0 / 5 - 0 ratings