Constructing a list of interfaces/unions in Dgraph

Say I have a schema like so:

type Basket{
	id: ID!
	fruits: [Fruit!]!
}

interface Fruit{
	id: ID!
}

type Apple implements Fruit{
    color: String!
}

There is currently no way to construct a list of fruits in place, since interfaces do not form an input type. Rather, we need a new mutation for each different type that we want to add to the list, and we store a list of their IDs. After this, we need one mutation at the end to construct the list using the IDs.

I’d love to have a way of constructing the list inline. If we don’t want to add new syntax, perhaps we could create an input type that would allow a mutation that looks like this:

mutation {
  addBasket(input: [{
    fruits: [
      {
        __typename: "Apple",
        color: "Green"
      }
    ]
  }]) { basket { id } }
}
3 Likes

Not sure if we can do something like this and accept a __typename inside mutations. I’d suggest re-modelling your schema to have Fruit as a type with a field for the type of fruit.

I think this illustrates how mutations with unions will work:

First let’s modify the schema a bit to have Oranges and cost for each Fruit:

type Basket{
	id: ID!
	fruits: [Fruit!]!
}

interface Fruit{
	id: ID!
	cost: Float!
}

type Apple implements Fruit{
    color: String!
}

type Orange implements Fruit {
    sournessLevel: Float! 
}

Now, Something like this doesn’t seem possible, because:

  1. inputs in GraphQL can’t be a union of different input types. This is as per spec. So, let’s say if we were to build the complete GraphQL schema like this:
    input AddBasketInput {
      fruits: [AddFruitInput]
    }
    union AddFruitInput = AddAppleInput | AddOrangeInput | ...
    
    Then, it would be an invalid GraphQL schema. Because unions can’t be inputs as per the GraphQL spec.
  2. The __typename approach also won’t be possible with interfaces, because well in addition to point 1 above, let’s say we just created AddFruitInput as an input type, like so:
    input AddFruitInput {
     cost: Float!
    }
    
    Then, it can only have fields that exist in the interface Fruit and not in any of its implementing types. And, as we can see, both type Apple and type Orange have a NON_NULL field. Now, if I add fruits with only the cost field, then it just doesn’t make sense. Because, at the end that Fruit is going to be one of Apple or Orange, and so it must be created with the NON_NULL fields in those concrete types, which won’t be present if we follow this approach.

But, as @amaster507 pointed, once Unions are available, you would be able to modify your schema like so:

interface Fruit{
	id: ID!
	cost: Float!
}

type Apple implements Fruit{
    color: String!
}

type Orange implements Fruit {
    sournessLevel: Float! 
}

union BasketFruit = Apple | Orange

type Basket{
	id: ID!
	fruits: [BasketFruit!]!
}

which should help you get the inline behavior you are looking for.

2 Likes

Thanks, I’ve linked an RFC there (Union types in GraphQL - #8 by ajeet).

While the GraphQL spec doesn’t currently have an input types for either of the two, they’re working on an RFC for unions. I suppose I’ll have to stick with unions for this kind of problem.