6

With graphql, enum can make a predefined list of elements but strings don't work.

For example:

enum Dias {
  lunes
  martes
  miércoles
  jueves
  viernes
  sábado
  domingo
}

This returns an error GraphQLError: Syntax Error: Cannot parse the unexpected character "\u00E9".

how is it possible to make a predefined list of strings?


Edit: to give more context, I want to reflect the database schema, which is like this (with mongoose):

dias: {
  type: String,
  enum: ['lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado', 'domingo'],
  lowercase: true,
  required: true
}

2 Answers 2

8

Your syntax is correct, the only issue is that the "é" and "á" characters are not supported. The specification outlines rules for naming operations, fields, etc. The supported pattern is:

/[_A-Za-z][_0-9A-Za-z]*/

Furthermore:

Names in GraphQL are limited to this ASCII subset of possible characters to support interoperation with as many other systems as possible.

So, unfortunately, you will have to convert those accented characters to valid ones in order for your schema to be considered valid.

EDIT: You could create a custom scalar. Here's a function that takes a name, description and an array and returns a custom scalar:

const makeCustomEnumScalar = (name, description, validValues) => {
  const checkValue = (value) => {
    const coerced = String(value)
    if (!validValues.includes(coerced)) {
      throw new TypeError(`${coerced} is not a valid value for scalar ${name}`)
    }
    return coerced  
  }
  return new GraphQLScalarType({
    name,
    description,
    serialize: checkValue,
    parseValue: checkValue,
    parseLiteral: (ast) => checkValue(ast.value),
  })
}

Now you can do something like:

const DayOfWeek = makeCustomEnumScalar('Day of Week', 'day of week enum', [
  'lunes',
  'martes',
  'miércoles',
  'jueves',
  'viernes',
  'sábado',
  'domingo'
])

Add it to your resolvers:

const resolvers = {
  DayOfWeek,
  // Query, Mutation, etc.
}

And your type definitions:

scalar DayOfWeek

And then you can use it like any other scalar. If an invalid value is provided as an input or output by a query, then GraphQL will throw an error like with an enum. The only caveat is that if you're entering the values directly into your query (as opposed to using variables), you'll still need to wrap them in double quotes.

Sign up to request clarification or add additional context in comments.

4 Comments

thank you for your answer. Like I explained in the question I already noted it is not working out-of-the box with enum. Your explanation is interesting, but this does not answer the question. I edited the question to add a bit more context
@FrançoisRomain please see my edited answer for an alternative approach
thank you very much, this works! One last thing: in graphiql, is it possible to have auto-complete on those value like a standard enum?
No, as far as I'm aware there's no way to do that since the valid values themselves will not be available via introspection. If you adopt this approach, it may be helpful to include the values in the description to at least document them that way
0

Just extending @Daniel-Rearden's answer :

All works like a charm (thank you!), just would like to note, that for me makeCustomEnumScalar required some different small tweaks (maybe lib version affects) :

1)The name "Day Of Week" should correspond to regex /^[_a-zA-Z][_a-zA-Z0-9]*$/

const DayOfWeek = makeCustomEnumScalar('Day of Week', 'day of week enum', [

so should be for example :

const DayOfWeek = makeCustomEnumScalar('DayofWeek', 'day of week enum', [

2)Just had a minimal changes relating types, so my variant is :

const makeCustomEnumScalar = (name:string, description:string, validValues:string[]) => {
  const checkValue = (value:ValueNode) => {
    const coerced = String(value)
    if (!validValues.includes(coerced)) {
      throw new TypeError(`${coerced} is not a valid value for scalar ${name}`)
    }
    return coerced  
  }
  return new GraphQLScalarType({
    name,
    description,
    serialize: checkValue,
    parseValue: checkValue,
    parseLiteral: (ast) => checkValue(ast),
  })
}

So providing full code listing :

import { GraphQLScalarType, ValueNode } from 'graphql';


const makeCustomEnumScalar = (name:string, description:string, validValues:string[]) => {
  const checkValue = (value:ValueNode) => {
    const coerced = String(value)
    if (!validValues.includes(coerced)) {
      throw new TypeError(`${coerced} is not a valid value for scalar ${name}`)
    }
    return coerced  
  }
  return new GraphQLScalarType({
    name,
    description,
    serialize: checkValue,
    parseValue: checkValue,
    parseLiteral: (ast) => checkValue(ast),
  })
}

export const DayOfWeek = makeCustomEnumScalar('DayOfWeek', 'day of week enum', [
    "My enum value 1",
    "My enum value 2"
    ])

export const typeDefs = gql`
  scalar DayOfWeek

  type StrEntity {
    id: ID!
    dayOfWeek: DayOfWeek!
  }
  
  extend type Mutation {
    getStrById(id: String!): StrEntity
  }
`;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.