2

I'd like to make every field private, unless otherwise notated with a directive. Is it possible to get this information within a resolve function?

const typeDefs = gql`
  directive @public on FIELD_DEFINITION

  type Query {
    viewer: User @public
    secret: String
  }

  type User {
    id: ID!
  }
`

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

addSchemaLevelResolveFunction(schema, (parent, args, params, info) => {
  // Not possible
  if (info.fieldName.directive === 'public') {
    return parent;
  }

  throw new Error('Authentication required...');
});

const server = new ApolloServer({ schema });
M. Walker
  • 603
  • 4
  • 14

1 Answers1

4

While there is a directives property on FieldNode object in the fieldNodes array, as far as I'm aware it's not populated with the directives that apply to that specific field.

Directives aren't really meant to be used as a flag for something that can be referenced in a resolver (schema level or otherwise). You may consider moving your logic inside the directive's visitFieldDefinition function:

const { defaultFieldResolver } = require('graphql')
const { SchemaDirectiveVisitor } = require('graphql-tools')

class PublicDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field) {
    const { resolve = defaultFieldResolver } = field
    field.resolve = async function (source, args, context, info) {
      if (someCondition) {
        throw new SomeError()
      }
      return resolve.apply(this, [source, args, context, info])
    }
  }
}

const schema = makeExecutableSchema({
  typeDefs,
  resolvers,
  schemaResolvers: {
    public: PublicDirective,
  },
})
Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183
  • Yeah, that works for something like a ``@private`` directive (public by default), but was hoping to find a way for the inverse. – M. Walker Dec 30 '18 at 16:29
  • Is there an easy way to automatically add directives to all fields (i.e. @private) at compilation time? – M. Walker Dec 30 '18 at 16:30
  • Ah, sorry didn't fully get what you were trying to do. You can have the directive inject some arbitrary property into the context, then check for that property's existence inside `addSchemaLevelResolveFunction` – Daniel Rearden Dec 30 '18 at 17:11