ardatan / ardatan/graphql-tools

Custom directive not working

Open
#4,027 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
5.4k
Forks
830
Avg merge
10h 59m
Merged PRs (30d)
45

Description

**Custom directive for input is not working in Apollo version 3**

**Description**
I'm following a tutorial at [graphql-tools for Enforcing value restrictions](https://www.graphql-tools.com/docs/schema-directives#enforcing-value-restrictions) to build a directive to validate length of string input.

```graphql
input AddCycleWorkInput {
name: String! @length(max: 10)
}
```
**Expected**
If the length's name input exceeds the specified, i hope throwing any ValidateError or Error

**My Environment:**

- OS: Windowns 10
- `@graphql-tools/utils: 8.1.1`
- `apollo-server-core: ^3.3.0`
- `typescript: ^4.4.3`
- `@graphql-tools/utils: 8.1.1`,

***Schema build***
```typescript
private static buildSchema(accountsGraphQL: any): GraphQLSchema {
// List directives.
const { lengthDirectiveTypeDefs, lengthDirectiveTransformer } = lengthDirective('length');

// Build schema.
let schema = makeExecutableSchema({
typeDefs: mergeTypeDefs([
lengthDirectiveTypeDefs, // This is problem
accountsGraphQL.typeDefs,
typeDefs
]),
resolvers: mergeResolvers([accountsGraphQL.resolvers, resolvers]),
schemaDirectives: {
...accountsGraphQL.schemaDirectives,
},
});
// needed to validate input fields!
schema = lengthDirectiveTransformer(schema);
return schema;
}
```

***Constructor of Apollo Server***
```typescript
const server = new ApolloServer({
schema: this.buildSchema(accountsGraphQL), // Schema build
context: accountsGraphQL.context,
uploads: false,
formatError: (error) => {
if (error) {
return {
message: error.message,
status: codeToStatus[error.extensions.code.toUpperCase()] || 400,
path: error.path
};
}
}
});
```
***Length directive***, to short you can watch [this link](https://www.graphql-tools.com/docs/schema-directives#enforcing-value-restrictions)
```typescript
export default function lengthDirective(directiveName: string) {
class LimitedLengthType extends GraphQLScalarType {
constructor(type: GraphQLScalarType, maxLength: number) {
super({
name: `${type.name}WithLengthAtMost${maxLength.toString()}`,
serialize(value: string) {
console.log("value1", value);
const newValue: string = type.serialize(value)
if (newValue.length > maxLength) {
throw new Error(`expected ${newValue.length.toString(10)} to be at most ${maxLength.toString(10)}`)
}
return newValue
},

parseValue(value: string) {
console.log("value2", value);
return type.parseValue(value)
},

parseLiteral(ast) {
return type.parseLiteral(ast, {})
}
})
}
}

const limitedLengthTypes: Record> = {}

function getLimitedLengthType(type: GraphQLScalarType, maxLength: number): GraphQLScalarType {
const limitedLengthTypesByTypeName = limitedLengthTypes[type.name]
if (!limitedLengthTypesByTypeName) {
const newType = new LimitedLengthType(type, maxLength)
limitedLengthTypes[type.name] = {}
limitedLengthTypes[type.name][maxLength] = newType
return newType
}

const limitedLengthType = limitedLengthTypesByTypeName[maxLength]
if (!limitedLengthType) {
const newType = new LimitedLengthType(type, maxLength)
limitedLengthTypesByTypeName[maxLength] = newType
return newType
}

return limitedLengthType
}

function wrapType | GraphQLInputFieldConfig>(
fieldConfig: F,
directiveArgumentMap: Record
): void {
if (isNonNullType(fieldConfig.type) && isScalarType(fieldConfig.type.ofType)) {
fieldConfig.type = getLimitedLengthType(fieldConfig.type.ofType, directiveArgumentMap['max'])
} else if (isScalarType(fieldConfig.type)) {
fieldConfig.type = getLimitedLengthType(fieldConfig.type, directiveArgumentMap['max'])
} else {
throw new Error(`Not a scalar type: ${fieldConfig.type.toString()}`)
}
}
return {
lengthDirectiveTypeDefs: `directive @${directiveName}(max: Int) on FIELD_DEFINITION | INPUT_FIELD_DEFINITION`,
lengthDirectiveTransformer: (schema: GraphQLSchema) =>
mapSchema(schema, {
[MapperKind.FIELD]: fieldConfig => {
const lengthDirective = getDirective(schema, fieldConfig, directiveName)?.[0]
if (lengthDirective) {
wrapType(fieldConfig, lengthDirective)
return fieldConfig
}
},
})
}
}
```
I know this is a bug of version 3 ApolloServer, but can other way to fix it. Please help me. Thanks a lot.

Contributor guide

Open the contributing guide

Research direction

Start at buildSchema and follow lengthDirectiveTransformer into the mapSchema configuration in the length directive. Reproduce the AddCycleWorkInput case with a name longer than 10 characters, then verify that the schema reports an error for the input and that the existing FIELD_DEFINITION behavior remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.