GraphQL - how to specify maximum String lengths in schema

Viewed 7035

I want to tell GraphQL that my 'serialNumber' field is a String with a length of between 1 and 20 characters. I know to use the ! in the schema to make a field Required, but can I tell GraphQL that there is also a maximum field length?

If I pass a null value in for a required String field, GraphQL will not accept it. I want it to behave the same way when it is passed a string that is longer than the maximum allowed length.

I have looked at doing this two ways: 1) Add a 'maxlength' attribute to the field definition in the schema.graphql file. or 2) Create a new type and assign it a maximum length.

I can't find any information on how to do it. Is is possible?

3 Answers

You can use directives:

directive @length(max: Int!) on FIELD_DEFINITION

input Payload {
  name: String! @length(max: 50)
}

There is no place for this type of specification in graphql (types) definitions.

You can use directives but they are not supported (and not standarized) by all graphql servers - it's left to specific implementation details - check your server docs.

For single fields you can simply apply this logic inside mutation resolver - just throw an error if conditions (input string length between 1 and 20) not met.

This is possible to implement using GraphQL custom types. You can define a type for each maximum length you want:

StringMaxLenTypes.js:

const logToConsoleToHelpMeUnderstand = false;
const { GraphQLScalarType, Kind } = require('graphql');
const parseStringMaxLenType = (value,maxLength) => {
  logToConsoleToHelpMeUnderstand && console.log('Checking variable passed to a query is a string and max ' + maxLength + 'chars',value)
  if (typeof value === 'string') {
    if (value.length <= maxLength) {
      return value;
    } else {
      throw new Error('parseCi' + maxLength + 'Type: String must not be more that ' + maxLength + ' characters. It is ' + value.length + ' characters');
    }
  } else {
    throw new Error('parseCi' + maxLength + 'Type: value must be of type String. It is of type \'' + typeof value + '\'');
  }
}
const parseStringMaxLen20Type = value => { return parseStringMaxLenType(value, 20) };
const parseStringMaxLen25Type = value => { return parseStringMaxLenType(value, 25) };
const parseStringMaxLen50Type = value => { return parseStringMaxLentype(value, 50) };
const parseStringMaxLen255Type = value => { return parseStringMaxLentype(value, 255) };
const parseStringMaxLen500Type = value => { return parseStringMaxLentype(value, 500) };


const serializeStringMaxLenType = (value, maxLength) => {
  /** the serialize methods are called when data is going to be sent to the client. This can return anything
   * of any type, as it will end up as JSON, but we check what is coming back from the database is a string 
   * and not too long.
   */
  logToConsoleToHelpMeUnderstand && console.log(`Checking value '${value}' is at most ${maxLength} chars before serialising for output from graphQL to a client (the OCCP gateway is the client)`);
  if (typeof value === 'string') {
    if (value.length <= maxLength) {
      return value;
    } else {
      throw new Error('serializeCi' + maxLength + 'Type: String must not be more that ' + maxLength + ' characters. It is ' + value.length + ' characters');
    }
  } else {
    throw new Error('serializeCi' + maxLength + 'Type: value must be of type String. It is of type \'' + typeof value + '\'');
  }
};
const serializeStringMaxLen20Type = (value) => { return serializeStringMaxLenType(value,20) };
const serializeStringMaxLen25Type = (value) => { return serializeStringMaxLenType(value,25) };
const serializeStringMaxLen50Type = (value) => { return serializeStringMaxLenType(value,50) };
const serializeStringMaxLen255Type = (value) => { return serializeStringMaxLenType(value,255) };
const serializeStringMaxLen500Type = (value) => { return serializeStringMaxLenType(value,500) };

const parseLiteralStringMaxLenType = (ast, maxLength) => {
  logToConsoleToHelpMeUnderstand && console.log('checking Abstract Syntax Tree value (these come from parameters in GraphQL queries) is not more than ' + maxLength + ' chars long',ast);
  // For input payload i.e. for mutation. ast stands for abstract syntax tree, which is the type of 
  if (ast.kind === Kind.STRING) {
  // Note the parseStringMaxLenType function throws errors, or returns a valid value, so there is no need to throw errors here.
    return parseStringMaxLenType(ast.value, maxLength)
  } else {
    throw new Error()
  }
};

const parseLiteralStringMaxLen20Type = (ast) => { return parseLiteralStringMaxLenType(ast, 20) }
const parseLiteralStringMaxLen25Type = (ast) => { return parseLiteralStringMaxLenType(ast, 25) }
const parseLiteralStringMaxLen50Type = (ast) => { return parseLiteralStringMaxLenType(ast, 50) }
const parseLiteralStringMaxLen255Type = (ast) => { return parseLiteralStringMaxLenType(ast, 255) }
const parseLiteralStringMaxLen500Type = (ast) => { return parseLiteralStringMaxLenType(ast, 500) }

const StringMaxLen20Type = new GraphQLScalarType({
  name: 'StringMaxLen20Type',
  description: 'String up to 20 Chars',
  serialize: serializeStringMaxLen20Type,
  parseValue: parseStringMaxLen20Type,
  parseLiteral: parseLiteralStringMaxLen20Type,
});

const StringMaxLen25Type = new GraphQLScalarType({
  name: 'StringMaxLen25Type',
  description: 'String up to 25 Chars',
  serialize: serializeStringMaxLen25Type,
  parseValue: parseStringMaxLen25Type,
  parseLiteral: parseLiteralStringMaxLen25Type,
});

const StringMaxLen50Type = new GraphQLScalarType({
  name: 'StringMaxLen50Type',
  description: 'String up to 50 Chars',
  serialize: serializeStringMaxLen50Type,
  parseValue: parseStringMaxLen50Type,
  parseLiteral: parseLiteralStringMaxLen50Type,
});

const StringMaxLen255Type = new GraphQLScalarType({
  name: 'StringMaxLen255Type',
  description: 'String up to 255 Chars',
  serialize: serializeStringMaxLen255Type,
  parseValue: parseStringMaxLen255Type,
  parseLiteral: parseLiteralStringMaxLen255Type,
});

const StringMaxLen500Type = new GraphQLScalarType({
  name: 'StringMaxLen500Type',
  description: 'String up to 500 Chars',
  serialize: serializeStringMaxLen500Type,
  parseValue: parseStringMaxLen500Type,
  parseLiteral: parseLiteralStringMaxLen500Type,
});

module.exports = {StringMaxLen20Type, StringMaxLen25Type, StringMaxLen50Type, StringMaxLen255Type, StringMaxLen500Type };

Then you need to define each of these types in your grapql.shema schema.graphql:

scalar StringMaxLen20Type
scalar StringMaxLen25Type
scalar StringMaxLen50Type
scalar StringMaxLen255Type
scalar StringMaxLen500Type
type YourOtherTypes {
  id: ID!
  canUseAboveTypesLikeThis: StringMaxLen50Type
}

And import them into your resolvers.js, and define them in the resolver object passed to your graphQL server : resolvers.js:

...
...
const {StringMaxLen20Type, StringMaxLen25Type, StringMaxLen50Type, StringMaxLen255Type, StringMaxLen500Type } = require('StringMaxLenTypes.js');```
...
module.exports = {
Query: {...},
Mutation: {...},
StringMaxLen20Type,
StringMaxLen25Type,
StringMaxLen50Type,
StringMaxLen255Type,
StringMaxLen500Type

This will then apply the same strict checking that GraphQL does all its data types to the maximum lengths.

Related