I want to be able to apply custom directives to the my mutation input variables. I’ve tried a variety of solutions, including the example given by graphql-tools, however, I haven’t been able to find anything that does the following:
When a mutation request is made, whatever is passed into the input fields should pass their variables into the directive’s code to validate that the condition(s) has/have been made before executing what is in the mutation’s resolver.
Perhaps the questions are:
- Can custom directives be applied to input fields for directives?
- If so, what modifications do I need to make to achieve the desired result?
Below is what I have so far. The length directive is the custom directive that I want to use in my mutation and the typedefs.js file is how I have my typedefs currently set up
lengthdirective.js
import { defaultFieldResolver } from "graphql"
import { getDirective, MapperKind, mapSchema } from "@graphql-tools/utils"
function lengthDirective(directiveName) {
const typeDirectiveArgumentMaps = {}
return {
lengthDirectiveTypeDefs: `
directive @${directiveName}(
min: Int,
max: Int,
exact: Int
) on FIELD_DEFINITION
`,
lengthDirectiveTransformer: (schema) =>
mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const lengthDirective = getDirective(schema, fieldConfig, directiveName)?.[0]
if (lengthDirective) {
const { min, max, exact } = lengthDirective
if (requires) {
const { resolve = defaultFieldResolver } = fieldConfig
fieldConfig.resolve = async function (source, args, context, info) {
const result = await resolve(source, args, context, info)
if (typeof result === 'string') {
if ((min !== undefined && result.length < min) || (max !== undefined && result.length > max) || (exact !== undefined && result.length !== exact)) {
let errorMessage = 'The length of the string'
if (min !== undefined) {
errorMessage += ` must be at least ${min} characters`
}
if (min !== undefined && max !== undefined) {
errorMessage != ' and'
}
if (max !== undefined) {
errorMessage += ` must be at most ${max} characters`
}
if (exact !== undefined) {
errorMessage += ` must be exactly ${exact} characters`
}
}
}
return result
}
return fieldConfig
}
}
}
})
}
}
const { lengthDirectiveTypeDefs, lengthDirectiveTransformer } = lengthDirective("length")
export { lengthDirectiveTypeDefs, lengthDirectiveTransformer }
typedefs.js
import { authDirectiveTypeDefs } from "./directives/authDirective.js";
import { lengthDirectiveTypeDefs } from "./directives/lengthDirective.js";
export const TYPE_DEFS = [
authDirectiveTypeDefs,
lengthDirectiveTypeDefs,
`
type Game {
id: ID!
title: String!
platform: [String!]!
reviews: [Review!]
}
type Review @auth(requires: ADMIN) {
id: ID!
rating: Int!
content: String!
author: Author!
game: Game!
}
type Author {
id: ID!
name: String!
verified: Boolean
reviews: [Review!]
}
type Query {
reviews: [Review]
review(id: ID!): Review
games: [Game]
game(id: ID!): Game
authors: [Author]
author(id: ID!): Author
}
type Mutation {
authenticate(name: String! @length(min: 5), password: String!): String
}
`
];