ardatan / ardatan/graphql-tools
Custom directive not working
- 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
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