(GraphQL) Interface TypeRef fields missing

Moved from GitHub dgraph/5697

Posted by CosmicPangolin:

What version of Dgraph are you using?

v20.03.3

Have you tried reproducing the issue with the latest release?

No, but I didn’t see a fix in a quick scan of the changelog :slight_smile:

What is the hardware spec (RAM, OS)?

GCloud VM 8gb

Steps to reproduce the issue (command/config used to run Dgraph).

Consider a schema with something like the following (this is probably more complicated than necessary, but it matches my case):

interface Post{
    thread: Thread! @hasInverse(field: posts)
    id: ID!
    type: String!  // Serialized type
    updatedTime: Int!
    createdTime: Int! @search
    replies: [Post!] @hasInverse(field: parentPost)
    parentPost: Post @hasInverse(field: replies)
    user: User!
}

Expected behaviour and actual result.

When Post is an interface, the PostRef generated only includes the id field. If we’re serializing data to produce mutation inputs, a PostRef input for parentPost requires serializing the relevant Post object with only an id, or an ‘undefined location’ error is thrown. I think concrete TypeRefs expose all first-order fields, which allows us a lot more convenience designing generic mutation methods for our data…we can serialize objects with some simple nested data to define edges, which feels pretty good (though I think the endpoint still rejects nested data w/ non-null predicates…see comment at the end).

But allowing fields in the TypeRef also specifically unlocks our ability to append the ‘type’ field as a discriminator during serialization, before our data hits the wire - the endpoint doesn’t reject our ‘type’ field in any other cases that I’m aware of.

A discriminator field is a common feature in serialization libraries, and core to our data systems design…so I hope it’s possible to squeeze this into 2020.07. We’ve realized it takes some serialization/modeling gymnastics to strip out discriminators from predicate objects in this case. Our easiest workaround is to manually identify mutations with interface fields, null the associated predicate objects before serialization, construct strings to represent them, stringify the serialized data, and splice the predicate representations back in :face_with_head_bandage:

This is a similar issue to the TypePatch object lacking the ‘id’ field - in that it’s largely a problem when building generified methods for handling data - but is much more difficult to work around because the discriminator field can’t easily be nulled, and is even required in most other queries/mutations since it’s used for deserialization.

I think ideally nested predicate fields should not get rejected either, and the endpoint would simply look at the ids of first order relations to draw edges…then we could pass any data object as-is for storage. The endpoint selectively rejecting fields defined in schema makes programmatically saving data unintuitive and difficult in general.

CosmicPangolin commented :

@MichaelJCompton

I have a hunch this is your domain, and I wanted to bump it to your attn 'cause you’ve been so responsive (<3) and it might be a really easy fix. While we’re working around other snags detailed elsewhere (subscriptions and ‘has edge’ filtering in particular), this one is almost blocking given the idiosyncrasy (yet prevalence) of the problem case and the manual + gymnastic nature of the workaround.