1
votes

I have a nested javascript class (see below) that is exposed through my GraphQL server. Can I write a GQL schema that exposes this complex structure as a single object? (aka flattened).

The Nested Object

interface Promotion {
    id
    type 
    data: PromotionType1 | PromotionType2 
}

interface PromotionType1 {
    a
    b 
}

interface PromotionType2 {
    c
    d
}

The desired GQL query to access the Object

I want to write a GQL schema so that I can query this object as follows:

promotion(id: "123") {
    id
    type
    ... on PromotionType1 {
        a
        b
    }
    ... on PromotionType2 {
        c
        d
    }
}

Is this possible with GQL?

2

2 Answers

1
votes

One possible solution is to flatten the object structure in your resolver. This would avoid the need to do anything complex in your GQL schema.

1
votes

You can use GraphQLUnitType and GraphQLInterfaceType to be able to make that GraphQL query to access the object, if you restructure your nested object. It seems you intended to use inheritance while designing promotion types and ended up having the subtypes as a field in parent type. Instead the structure should be like:

interface Promotion {
    id
    type 
}

interface PromotionType1 extends Promotion {
    a
    b 
}

interface PromotionType2 extends Promotion {
    c
    d
}

Promotion is the base type. We can have it as GraphQLInterfaceType:

const PromotionType = new GraphQLInterfaceType({
  name: 'PromotionInterface',
  fields: {
    id: { type: GraphQLID },
    type: { type: GraphQLString }
  }
});

You need instances of PromotionType1 and PromotionType2. So, these can be GraphQLObjectType.

const PromotionType1 = new GraphQLObjectType({
  name: 'PromotionType1',
  interfaces: [ PromotionType ],
  fields: {
    id: { type: GraphQLID },
    type: { type: GraphQLString },
    a: { type: GraphQLString },
    b: { type: GraphQLString },
  },
  isTypeOf: value => value instanceof PromotionType1
});

const PromotionType2 = new GraphQLObjectType({
  name: 'PromotionType2',
  interfaces: [ PromotionType ],
  fields: {
    id: { type: GraphQLID },
    type: { type: GraphQLString },
    c: { type: GraphQLString },
    d: { type: GraphQLString },
  },
  isTypeOf: value => value instanceof PromotionType2
});

If your have JS class Promotion1 for GraphQL type PromotionType1 and Promotion2 for PromotionType2, the GraphQLObjectType for exposing promotion data will be like:

var Promotion = new GraphQLUnionType({
  name: 'Promotion',
  types: [ PromotionType1, PromotionType2 ],
  resolveType(value) {
    if (value instanceof Promotion1) {
      return PromotionType1;
    }
    if (value instanceof Promotion2) {
      return PromotionType2;
    }
  }
});

You can then query promotion data with:

promotion(id: "123") {
    id,
    type,
    ... on PromotionType1 {
        a,
        b,
    }
    ... on PromotionType2 {
        c,
        d,
    }
}

You can check out this example.