smooth-code / graphql-directive

Use custom directives in your GraphQL schema and queries 🎩
MIT License
152 stars 14 forks source link

addDirectiveResolveFunctionsToSchema breaks default behavior of @skip and @include #12

Closed sbogdaniuk closed 5 years ago

sbogdaniuk commented 5 years ago

Hi guys. I'm trying to implement my custom directives, and this package makes process so easy, but I've discovered that it breaks default behavior of @inclue and @skip

How to reproduce

Lets' take simple start app, from graphql-server-example. Change code little bit, and when I wrap schema with custom directive resolvers using addDirectiveResolveFunctionsToSchema, it breaks @skip(if: false) and @include(if: true), while @include(if: false) and @skip(if: true) still work.

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

// This is a (sample) collection of books we'll be able to query
// the GraphQL server for.  A more complete example might fetch
// from an existing data source like a REST API or database.
const books = [
  {
    title: 'Harry Potter and the Chamber of Secrets',
    author: 'J.K. Rowling',
  },
  {
    title: 'Jurassic Park',
    author: 'Michael Crichton',
  },
]

// Type definitions define the "shape" of your data and specify
// which ways the data can be fetched from the GraphQL server.
const typeDefs = gql`
  directive @upper on FIELD | FIELD_DEFINITION

  # Comments in GraphQL are defined with the hash (#) symbol.

  # This "Book" type can be used in other type declarations.
  type Book {
    title: String
    author: String
  }

  # The "Query" type is the root of all GraphQL queries.
  # (A "Mutation" type will be covered later on.)
  type Query {
    books: [Book]
  }
`

// Resolvers define the technique for fetching the types in the
// schema.  We'll retrieve books from the "books" array above.
const resolvers = {
  Query: {
    books: () => books,
  },
}

const directiveResolvers = {
  async upper (resolve, source, args, { locale }) {
    const value = await resolve()

    if (typeof value === 'string') {
      return value.toUpperCase()
    }

    return value
  },
}

const schema = makeExecutableSchema({
  typeDefs,
  resolvers,
})

addDirectiveResolveFunctionsToSchema(schema, directiveResolvers)

// In the most basic sense, the ApolloServer can be started
// by passing type definitions (typeDefs) and the resolvers
// responsible for fetching the data for those types.
const server = new ApolloServer({
  schema,
  engine: process.env.ENGINE_API_KEY && {
    apiKey: process.env.ENGINE_API_KEY,
  },
})

// This `listen` method launches a web-server.  Existing apps
// can utilize middleware options, which we'll discuss later.
server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`)
})

It throw error

"extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "TypeError: directiveInfo.resolver is not a function",
...

Do I miss something? Thanks.

gregberge commented 5 years ago

I am not actively using this package, maybe someone could help you to figure out what's going on.