# Correct implementation of an interface

**URL:** <https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813>\
**Category:** Dgraph\
**Tags:** kind:question, dql, area:interface\
**Created:** [September 29, 2022, 9:01pm UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813 "2022-09-29T21:01:02Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Poolshark](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/poolshark/32/10074_2.png) [@Poolshark](https://discuss.dgraph.io/u/Poolshark)\
**Post date:** [September 29, 2022, 9:01pm UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813/1 "2022-09-29T21:01:02Z")

</div>

I have experienced a very strange behaviour - or at least I do not understand how Dgraph want’s this to be implemented - when it comes to interfaces. I guess it is partly related to [this thread.](http://discuss.hypermode.com/t/interfaces-are-not-graphql-compliant/9725/13)

According to the [GraphQL specs](https://graphql.org/learn/schema/)

> An _Interface_ is an abstract type that includes a certain set of fields that a type must include to implement the interface.

and

> This means that any type that _implements_ the interface needs to have the **exact same fields as the interface** , with these arguments and return types.

So far, so good. Let’s assume the following schema

```auto
# Schema ---

# The interface with some searchable fields
interface Implement {
  id: ID!
  some: String! @id
  more: String! @id
  fields: String @search
}

# Type One, which implements all the fields according to the specs
type One implements Implement {
  id: ID!
  one: Int
  
  # Implemented
  some: String! @id
  more: String! @id
  fields: String @search
}

# Type Two, which also implements the interface but I did not set the fields specifically 
type Two implements Implement {
  id: ID!
	two: Int
	
  # Implemented
  # some: String @id
  # more: String @id
  # fields: String @search
}

```

### DQL Mutation to populate the database

I’m running a **DQL mutation** to populate the database. Since the interface itself should be queryable _(and has an ID)_, I need to set both types `One` and `Implement` or `Two` and `Implement` when setting both types `One` and `Two`. Since the additional fields are implemented via the interface `Implement`, the predicate must be set to `Implement.some`, `Implement.more`, etc.

```auto
{
    "set": [
        {
            "uid": "_:nOneUid",
            "dgraph.type": ["One", "Implement"],
            "One.one": 1,

            "Implement.some": "unique_1",
            "Implement.more": "unique_2",
            "Implement.fields": "text for one"
        },
        {
            "uid": "_:nTwoUid",
            "dgraph.type": ["Two", "Implement"],
            "Two.two": 2,

            "Implement.some": "unique_3",
            "Implement.more": "unique_4",
            "Implement.fields": "text for two"
        }
    ]
}

```

### Query results

Now I’ve run the queries for each **type** and the **interface**. It pretty much does exactly what I would expect. Both `One` and `Two` inherit both types `One`/`Two` and `Implement`. The **value** for the interface field `some`, is only accessible via `Interface.some` _(this is clear since I did not define any other predicate in my DQL mutation)_.

```auto
# Query ---

{
    qOne(func: type(One)) {
        uid
        dgraph.type
        Implement.some
        One.some
    }

    qTwo(func: type(Two)) {
        uid
        dgraph.type
        Implement.some
        Two.some
    }

    qImplement(func: type(Implement)) {
        uid
        dgraph.type
        Implement.some
    }
}

```

The **query result** gives

```auto
{
  data: {
    qOne: [
      0: {
        uid: "0x1a4863389c"
        dgraph.type: [
          0: "One"
          1: "Implement"
        ]
        Implement.some: "unique_1"
      }
    ]
    qTwo: [
      0: {
        uid: "0x1a4863389d"
        dgraph.type: [
          0: "Two"
          1: "Implement"
         ]
         Implement.some: "unique_3"
       }
     ]
     qImplement: [
       0: {
         uid: "0x1a4863389c"
         dgraph.type: [
           0: "One"
           1: "Implement"
         ]
         Implement.some: "unique_1"
       }
      1: {
        uid: "0x1a4863389d"
        dgraph.type: [
          0: "Two"
          1: "Implement"
        ]
        Implement.some: "unique_3"
      }
   ]
}

```

### The Dgraph Cloud Data Studio

This is where I first realised there is something different with the 2 types I have just set up.

Type `One` can be sorted by

- `one`
- `some`
- `more`
- `fields`

 ![Data Studio for type One](https://canada1.discourse-cdn.com/flex007/uploads/dgraph/original/2X/d/d4627ef0ec8e1cf2a15a5f165e6f4a3281b07831.jpeg)

but type `Two` only has a sorting option for

- `two`

 ![Data Studio fro type Two](https://canada1.discourse-cdn.com/flex007/uploads/dgraph/original/2X/d/d9ce762e20141490185e6e40943378e331bf243a.png)

Furthermore, if I set the **sort parameter** to eg. `some` for type `One`, the **DQL query fails** and I get the

> Failed to retrieve the data

error.

 ![Data Studio - Sorting by for type One](https://canada1.discourse-cdn.com/flex007/uploads/dgraph/original/2X/e/eb8856341e9b35a19e6e6f18b9e3dd8eb9e667c1.png)

The Network tab reveals

```auto
{
    "errors": [
        {
            "message": ": Cannot sort by unknown attribute One.more",
            "extensions": {
                "code": "ErrorInvalidRequest"
            }
        }
    ],
    "data": null
}

```

that Dgraph is looking for the predicate `One.some`, which obviously does not exist! This means that when actively implementing the interface fields into the type, somehow makes Dgraph “expect” that both predicates, “One.some” and “Interface.some” must exist.

Both implementations in the schema are GraphQL compliant if I’m not mistaken! So which is the right implementation? Would I have to add the missing predicates for type `One`? So sth. like this

```auto
{
    "set": [
        {
            "uid": "_:nOneUid",
            "dgraph.type": ["One", "Implement"],
            "One.one": 1,

            "Implement.some": "unique_1",
            "Implement.more": "unique_2",
            "Implement.fields": "text for one",

            "One.some": "unique_1",
            "One.more": "unique_2",
            "One.fields": "text for one"
        }
    ]
}

```

I’m really confused! 🙈 Any help appreciated.

---

<div class="post-metadata">

**Author:** ![Poolshark](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/poolshark/32/10074_2.png) [@Poolshark](https://discuss.dgraph.io/u/Poolshark)\
**Post date:** [September 30, 2022, 3:35pm UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813/2 "2022-09-30T15:35:43Z")

</div>

## Update

I have done some further investigation on this topic and it seems that Dgraph’s implementation of interfaces is NOT GraphQL compliant!

### Tests

Since my naming in the last post was pretty confusing, I’ve tried to clean things up a bit and changed the schema to a hopefully more readable form

```auto
# Schema ---

interface Animal {
  id: ID!
  name: String! @id
}

type Dog implements Animal {
  id: ID!
  breed: String
  name: String! @id
}

type Cat implements Animal {
  id: ID!
  colour: String
}

type Ant implements Animal {
  hasVenom: Boolean
}

```

**I have covered all three possible cases here:**

1. `Dog` → Repetition of **all fields of the interface**
2. `Cat` → Repetition of **only the ID field** of the inter face
3. `Ant` → **No repetition** of any of the interface fields

Number 1 is the GraphQL conform implementation and 2/3 are _“internally extended”_ by Dgraph to match the compliance. All implementations should be returning the **same results** when querying for the type. Unfortunately, this is not the case!

### Mutations

I have also run two sets of mutations, a DQL and a GraphQL mutation, for each of the types. The DQL mutations represent my understanding of how Dgraph represents the interface implementation in the database. The GraphQL queries are just a test how Dgraph does actually save the data.

> **DQL mutation**
>
> ```auto
> # DQL Mutation
> 
> {
> "set": [
> {
> "uid": "_:nDogUid",
> "dgraph.type": ["Dog", "Animal"],
> "Dog.breed": "Bulldog",
> "Animal.name": "Bully"
> },
> {
> "uid": "_:nCatUid",
> "dgraph.type": ["Cat", "Animal"],
> "Cat.colour": "black",
> "Animal.name": "Kitty"
> },
> {
> "uid": "_:nAntUid",
> "dgraph.type": ["Animal"],
> "Ant.hasVenom": true,
> "Animal.name": "Badboy"
> }
> ]
> }
> 
> ```

> **GraphQL mutations**
>
> ```auto
> # GraphQL Mutations ---
> 
> mutation AddDog {
> addDog(
> input: {
> breed: "Labrador",
> name: "Bernie"
> }
> ) {
> numUids
> }
> }
> 
> mutation AddCat {
> addCat(
> input: {
> colour: "white",
> name: "Snowflake"
> }
> ) {
> numUids
> }
> }
> 
> mutation AddAnt {
> addAnt(
> input: {
> hasVenom: false,
> name: "Goodboy"
> }
> ) {
> numUids
> }
> }
> 
> ```

### Query Results

This is where it gets interesting. Again I have different sorting options for `Dog` vs `Cat`, with the failing DQL query for `Dog.name`. The `Ant` _Badboy_ which was created via DQL does not show up in theData Studio at all, the via GraphQL created _Goodboy_ does.

If I run a DQL query on all the types for all possible predicates

```auto
# DQL Query ---
{
    qAnimal(func: type(Animal)) {
        dgraph.type
        Animal.name
        
    }

    qDog(func: type(Dog)) {
        dgraph.type
        Animal.name
        Dog.name
        Dog.breed 
    }

    qCat(func: type(Cat)) {
        dgraph.type
        Animal.name
        Cat.name
        Cat.colour 
    }

    qAnt(func: type(Ant)) {
        dgraph.type
        Animal.name
        Ant.name
        Ant.hasVenom 
    }
}

```

I get this result

```auto
# Result ---

{
  "data": {
    "qAnimal": [
      {
        "dgraph.type": [
          "Cat",
          "Animal"
        ],
        "Animal.name": "Kitty"
      },
      {
        "dgraph.type": [
          "Animal"
        ],
        "Animal.name": "Badboy"
      },
      {
        "dgraph.type": [
          "Animal",
          "Dog"
        ],
        "Animal.name": "Bully"
      },
      {
        "dgraph.type": [
          "Animal",
          "Dog"
        ],
        "Animal.name": "Bernie"
      },
      {
        "dgraph.type": [
          "Cat",
          "Animal"
        ],
        "Animal.name": "Snowflake"
      },
      {
        "dgraph.type": [
          "Animal",
          "Ant"
        ],
        "Animal.name": "Goodboy"
      }
    ],
    "qDog": [
      {
        "dgraph.type": [
          "Animal",
          "Dog"
        ],
        "Animal.name": "Bully",
        "Dog.breed": "Bulldog"
      },
      {
        "dgraph.type": [
          "Animal",
          "Dog"
        ],
        "Animal.name": "Bernie",
        "Dog.breed": "Labrador"
      }
    ],
    "qCat": [
      {
        "dgraph.type": [
          "Cat",
          "Animal"
        ],
        "Animal.name": "Kitty",
        "Cat.colour": "black"
      },
      {
        "dgraph.type": [
          "Cat",
          "Animal"
        ],
        "Animal.name": "Snowflake",
        "Cat.colour": "white"
      }
    ],
    "qAnt": [
      {
        "dgraph.type": [
          "Animal",
          "Ant"
        ],
        "Animal.name": "Goodboy",
        "Ant.hasVenom": false
      }
    ]
  },
  "extensions": {
    "server_latency": {
      "parsing_ns": 105492,
      "processing_ns": 3208408,
      "encoding_ns": 85736,
      "assign_timestamp_ns": 453735,
      "total_ns": 3947158
    },
    "txn": {
      "start_ts": 249258010,
      "hash": "63e299bd98e4e5e57eb732ceb9ed3e716fcda7bc939ad10affe7a41d22371ffc"
    },
    "metrics": {
      "num_uids": {
        "Animal.name": 11,
        "Ant.hasVenom": 1,
        "Ant.name": 1,
        "Cat.colour": 2,
        "Cat.name": 2,
        "Dog.breed": 2,
        "Dog.name": 2,
        "_total": 32,
        "dgraph.type": 11
      }
    }
  }
}

```

### Conclusion

**The implementation in `Dog` leads to false results** since there will be two different predicates

- `Dog.name` and
- `Animal.name`

Although, it might be the **most correct implementation** since Dgraph needs a representation for every predicate and `Dog.name` and `Animal.name` is valid. Unfortunately, Dgraph’s own GraphQL mutation does not create the predicate `Dog.name` and in custom DQL mutations we would have to type out every field which has been implemented via the interface for each type _(Animal, Dog)._

**The implementation in `Cat` is probably the one to go for.** Dgraph probably does exactly this in a GraphQL mutation.

**The implementation in `Ant`** is probably similar to `Cat` but a bit more confusing, Dgraph always assigns a UID for each type so basically you also end up with `id` two times implemented.

---

<div class="post-metadata">

**Author:** ![amaster507](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/amaster507/32/4123_2.png) [@amaster507](https://discuss.dgraph.io/u/amaster507)\
**Post date:** [September 30, 2022, 5:03pm UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813/3 "2022-09-30T17:03:37Z")

</div>

> [@Poolshark](#):
>
> it seems that Dgraph’s implementation of interfaces is NOT GraphQL compliant!

Correct. It is simplified on the SDL side of things but spec compliance with the served schema.

In Dgraph an implementation of an interface automatically includes all fields of the interface.

This simplifies typing and directives.

---

<div class="post-metadata">

**Author:** ![Poolshark](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/poolshark/32/10074_2.png) [@Poolshark](https://discuss.dgraph.io/u/Poolshark)\
**Post date:** [September 30, 2022, 6:40pm UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813/4 "2022-09-30T18:40:17Z")

</div>

> [@amaster507](#):
>
> In Dgraph an implementation of an interface automatically includes all fields of the interface.

I do not agree that this simplifies anything! In my opinion it makes things much more complicated or at least more confusing. It is nowhere stated that we are “not allowed” to type out the fields which are implemented via the interface - **especially when this is the regular GraphQL syntax.**

---

<div class="post-metadata">

**Author:** ![amaster507](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/amaster507/32/4123_2.png) [@amaster507](https://discuss.dgraph.io/u/amaster507)\
**Post date:** [September 30, 2022, 9:14pm UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813/5 "2022-09-30T21:14:04Z")

</div>

> [@Interfaces are not GraphQL compliant](http://discuss.hypermode.com/t/interfaces-are-not-graphql-compliant/9725):
>
> This is how the [GraphQL spec](http://spec.graphql.org/draft/#sec-Interfaces) defines interfaces: interface NamedEntity { name: String } type Person implements NamedEntity { name: String age: Int } Notice how the name field is repeated in the type implementing the interface. Not doing so is an error. In Dgraph, however, we omit the repeated field: interface NamedEntity { name: String } type Person implements NamedEntity { age: Int } At first, this doesn’t come across as a major problem - I personally found it redundant to speci…

---

<div class="post-metadata">

**Author:** ![Poolshark](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/poolshark/32/10074_2.png) [@Poolshark](https://discuss.dgraph.io/u/Poolshark)\
**Post date:** [October 1, 2022, 7:07am UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813/6 "2022-10-01T07:07:35Z")

</div>

So if I understand correctly my problem is a follow up of the original thread.

> [@Interfaces are not GraphQL compliant](http://discuss.hypermode.com/t/interfaces-are-not-graphql-compliant/9725/15):
>
> Hi @spinelsun, We added support to repeat the field names in implementing type and interface given that they are of same type and have same nullable condition. If field in interface have some directive then field in implementing type will inherit that directive.
> 
> And having same field name in multiple implementing interfaces is not allowed except `ID` type.This fix is currently avaliable in master branch and will also be avaliable in 20.11 release.

So field repetition is allowed but it causes **different implementations** to a case where we omit the fields. And this should **simply NOT be the case!** However the interpretation of Dgraph’s _“valid GraphQL"_ schema is, the representation of it **should not change with the way we write out the schema.**

So either Dgraph should always automatically generate the predicates for the missing type

- `Dog.name`
- `Cat.name` and
- `Ant.name`

or there is only one predicate, `Animal.name` for all the types which implement the interface - even when repeating the fields.

---

<div class="post-metadata">

**Author:** ![Poolshark](https://yyz1.discourse-cdn.com/flex007/user_avatar/discuss.dgraph.io/poolshark/32/10074_2.png) [@Poolshark](https://discuss.dgraph.io/u/Poolshark)\
**Post date:** [October 5, 2022, 7:25pm UTC](https://discuss.dgraph.io/t/correct-implementation-of-an-interface/17813/7 "2022-10-05T19:25:39Z")

</div>

### Follow-up

I know it is a small community and people here are trying their best to answer questions and help unexperienced users like me out. But I’m wondering if this forum is mainly hosted by people who do not use or do not a connection to the Cloud product. I guess this is still the main focus of Dgraph since it seems to be the way Dgraph earns money.

I have submitted various “problems” which - at least in my opinion - seemed to be bugs. So far only one of them has been implemented or taken care of. I really like the product and I can really see the potential but for me as a paying customer it seems a bit out of scope to personally identify problems and spend days to figure out why something is not working.

So posts like this (and unfortunately also support tickets) get “ghosted” very quickly and thus unanswered which often leaves me with some “workaround solution” I had to come up with. I am not saying that Dgraph should be able to 100% fulfil my business logic but at least some things which are at least worth a discussion should be handled a bit more professionally.

**So, regarding my question:**

- the implementation can break the Data Studio so (even if not a crucial feature) it would be awesome if there is at least a guideline of how we should implement interfaces.
- it is a difference if we repeat the fields or not and therefore I think this should be fixed in one way or the other

Maybe I’m wrong and I don’t want to offend anyone here! It’s not so many posts and it would be awesome if one of the DEVs or so would focus more on getting (at least bug reports) solved.

I am also more than willing to contribute as much as I can with my limited knowledge! 😛

@MichelDiz @akon @matthewmcneely @mrjn @koppula @ashwin95r @pawan @rarvikar
