graphql-field-arguments-coercion
TypeScript icon, indicating that this package has built-in type declarations

1.1.1 • Public • Published

graphql-field-arguments-coercion

npm version

Implementation of the support of coerce function on GraphQL Input types.

Used to implement directive-based validation and transformation of field arguments.

Originally developed by Alexandre Lacheze who was kind enough to transfer the repository and npm package for future development.

Install

npm install graphql-field-arguments-coercion -D

Usage

Use coerceFieldArgumentsValues(field, args, ...) to coerce the arguments of the given field. To coerce the arguments' values, it will recursively use the coerce property, a coercer function, hold by ArgumentDefinition, InputObject and InputObjectField.

A coercer function receives 4 arguments:

  • value: the value to be coerced.
  • context: the GraphQLContext of the current execution
  • inputCoerceInfo: an object holding info about the current argument, input or input field. See its type definition for more details.
  • fieldResolveInfo: the received GraphQLResolveInfo of the field being resolved.

A coercer function can return the coerced value, a promise resolving the coerced value or throw an error.

Example

Here's an implementation of a directive-based length validation @length(max: Int!):

First, we need to add the coercer to evey argument definition and input definition targeted by the directive. To do so, we use graphql-tools's SchemaDirectiveVisitor.

const directiveTypeDefs =  `
directive @length(max: Int!) on INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
`;

class LengthDirective<TContext> extends SchemaDirectiveVisitor<{ max: number }, TContext> {
  visitInputFieldDefinition(field: CoercibleGraphQLInputField<string, TContext>) {
    this.installCoercer(field);
  }

  visitArgumentDefinition(argument: CoercibleGraphQLArgument<string, TContext>) {
    this.installCoercer(argument);
  }

  installCoercer(
    input: 
      CoercibleGraphQLInputField<string, TContext> |
      CoercibleGraphQLArgument<string, TContext>
    ) {
      const { coerce = defaultCoercer } = input;
      input.coerce = async (value, ...args) => {
        // call previous coercers if any
        if (coerce) value = await coerce(value, ...args);

        const { path } = args[1]; // inputCoerceInfo
        const { max } = this.args;
        assert.isAtMost(value.length, max, `${pathToArray(path).join('.')} length exceeds ${max}`);

        return value;
      }
  }
}

We define the schema as usual but add the directive:

const typeDefs = `
type Query {
  books: [Book]
}

type Book {
  title: String
}

type Mutation {
  createBook(book: BookInput): Book
}

input BookInput {
  title: String! @length(max: 50)
}`;

const schema = makeExecutableSchema({
  typeDefs: [directiveTypeDefs, typeDefs],
  resolvers: {
    Mutation: {
      createBook: (_, { book }) => book,
    }
  },
  schemaDirectives: {
    length: LengthDirective
  }
});

Now we'll wrap all fields' resolvers with a use of coerceFieldArgumentsValues so that we make sure the arguments are valid before calling the resolver — otherwise, we throw the appropriate error.

To do so, we'll use graphql-tools's visitSchema and SchemaVisitor:

class FieldResoverWrapperVisitor<TContext> extends SchemaVisitor {
  visitFieldDefinition(field: GraphQLField<any, TContext>) {
    const { resolve = defaultFieldResolver } = field;
    field.resolve = async (parent, argumentValues, context, info) => {

      const coercionErrors: Error[] = [];
      const onCoercionError = e => coercionErrors.push(e);

      const coercedArgumentValues = await coerceFieldArgumentsValues(
        field,
        argumentValues,
        context,
        info,
        onCoercionError,
      );

      if (coercionErrors.length > 0) {
        throw new UserInputError(`Arguments are incorrect: ${coercionErrors.join(',')}`);
      }

      return resolve(parent, coercedArgumentValues, context, info);
    }
  }
}

visitSchema(schema, new FieldResoverWrapperVisitor);

The full example is runnable here.

Related

Readme

Keywords

Package Sidebar

Install

npm i graphql-field-arguments-coercion

Weekly Downloads

10

Version

1.1.1

License

MIT

Unpacked Size

59.7 kB

Total Files

16

Last publish

Collaborators

  • niklaskorz