How to reference a specific ENUM value in GraphQL type?
Asked Answered
G

3

13

I have the following schema:

enum PaymentTypeName {
  PAYMENT_CARD
  PAYMENT_CARD_TOKEN
}

interface Payment {
  id: ID!
  type: PaymentTypeName!
}

type PaymentCardPayment implements Payment {
  id: ID!
  type: PaymentTypeName!
  card: PaymentCard!
}

type PaymentCardTokenPayment implements Payment {
  id: ID!
  type: PaymentTypeName!
  card: PaymentCard!
}

When Payment is PaymentCardPayment or PaymentCardTokenPayment is determined by the value of type, i.e. it is either PAYMENT_CARD or PAYMENT_CARD_TOKEN.

How do I signify in the interface, that PaymentCardPayment/ PaymentCardTokenPayment inherit a specific value of PaymentTypeName?

I have tried various combinations of:

type PaymentCardPayment implements Payment {
  id: ID!
  type: PaymentTypeName.PAYMENT_CARD!
  card: PaymentCard!
}

and:

type PaymentCardPayment implements Payment {
  id: ID!
  type: PaymentTypeName[PAYMENT_CARD]!
  card: PaymentCard!
}

but all of these prompt a syntax error and I was unable to find the relevant documentation.

Gloriane answered 9/6, 2017 at 13:30 Comment(1)
did you find some sort of a solution?Yelena
S
5

What you're trying to do is not supported in GraphQL. If a field's type is declared to be PaymentTypeName, and PAYMENT_CARD and PAYMENT_CARD_TOKEN are both valid values of PaymentTypeName, then they must also be valid values for that field. There is no way to take an existing type9 whether it's an enum, scalar, or object type) and conditionally create a subset of possible values from the set of possible values already defined by the type.

That said, if PaymentCardPayment.type will always resolve to PAYMENT_CARD and PaymentCardTokenPayment.type will always resolve to PAYMENT_CARD_TOKEN, then it doesn't really make sense to use an enum here at all. In fact, in this specific case, we can omit the type field entirely. After all, the only purpose of the field in this case is to allow the client to distinguish between the possible types that Payment may resolve to. However, GraphQL already provides us with a __typename field that does just that by resolving to the name of the resolved type.

So in this specific instance, it's sufficient to just do:

interface Payment {
  id: ID!
}

type PaymentCardPayment implements Payment {
  id: ID!
  card: PaymentCard!
}

type PaymentCardTokenPayment implements Payment {
  id: ID!
  card: PaymentCard!
}

and query a field whose type is Payment like this:

{
  payments {
    id
    __typename
    ... on PaymentCardPayment {
      card {
        # ...
      }
    }
    ... on PaymentCardTokenPayment {
      card {
        # ...
      }
    }
  }
}
Sudduth answered 21/11, 2020 at 1:37 Comment(0)
P
2

You are trying to declare the field value in your type schema, which is not what a schema is meant for. You should only be declaring your field type within your schema, in this case it is just type: PaymentTypeName. You have it correct in your first code block.

Your PaymentCardPayment's type resolver function should return the value of the enum, in your case, PAYMENT_CARD.

Your PaymentCardTokenPayment's type resolver function should return the value of PAYMENT_CARD_TOKEN.

Pard answered 9/6, 2017 at 14:35 Comment(3)
I disagree. ENUM is a special case. PaymentType context it makes sense that type can inherit any of the PaymentTypeName values. However, in the context of PaymentCardPayment it is misleading to say that the value is either of the ENUM values; it is not. It is a constant value thats a subset of PaymentTypeName.Gloriane
Have to agree, refining that the subset will always be a static value from the ENUM that the interface guarantees makes sense and is likely one of the common ways that ENUM would be used when not being used for filtering via input types.Galop
So have you found a solution for this?Dansby
K
0

Edit: This only works on input types.

enum PaymentTypeName {
  PAYMENT_CARD
  WAD_OF_CASH
} 
 
input BuySomethingInput {
  method: PaymentTypeName! = WAD_OF_CASH
  price: Number
}

and then use the input type in a Mutation.

The following is not going to work

Would using a default value work for you?

type PaymentCardPayment implements Payment {
  id: ID!
  type: PaymentTypeName! = PAYMENT_CARD
  card: PaymentCard!
}  

It won't prevent you from overwriting the value but at least it should be set correctly.

Kristoforo answered 9/3, 2019 at 20:11 Comment(2)
This would be great. But I get a syntax error - are you sure this works?Giron
My mistake - this only works on input types. I'm updating the answer.Kristoforo

© 2022 - 2024 — McMap. All rights reserved.