How to force required fields?

What I want to do

I am experimenting with simple features of dgraph. I declared a schema with required fields. However, when I add a mutation via play.dgraph.io/?local, it ignores the required constraint.

What I did

Consider the following schema:

type BlogPost {
  id: ID!
  title: String!
  content: String!
  hasAuthor: Author!
}

type Author {
  id: ID!
  name: String!
  hasBlog: [BlogPost]
}

According to the documentation, adding the exclamation point after the field type such as String! makes it a required field. Logically, every Author has to have a name and id.

I then submitted the schema via curl

I can now run mutations in my console such as the following:

{
  set {
    _:user <dgraph.type> "Author" .
    _:user <Author.name> "User1" .
  }
}

Which returns a success message:

{
  "data": {
    "code": "Success",
    "message": "Done",
    "queries": null,
    "uids": {
      "user": "0x4e91"
    }
...

But I can also run this mutation:

{
  set {
    _:user <dgraph.type> "Author" .
    _:user <name> "User2" .
  }
}

Which also yields a positive result:

{
  "data": {
    "code": "Success",
    "message": "Done",
    "queries": null,
    "uids": {
      "user": "0x4e92"
    }
...

Isn’t the whole point of the schema to enforce data consistency? If I now run a query such as:

{
  node(func: type(Author)) {
    uid
    expand(_all_)
  }
}

it returns both Authors, but the second one has no name field:

{
  "data": {
    "node": [
      {
        "uid": "0x4e91",
        "Author.name": "User1"
      },
      {
        "uid": "0x4e92"
      }
    ]
  }
....

Dgraph metadata

dgraph version

Dgraph version : v21.03.0
Dgraph codename : rocket
Dgraph SHA-256 : b4e4c77011e2938e9da197395dbce91d0c6ebb83d383b190f5b70201836a773f
Commit SHA-1 : a77bbe8ae
Commit timestamp : 2021-04-07 21:36:38 +0530
Branch : HEAD
Go version : go1.16.2
jemalloc enabled : true

schema

<Author.hasBlog>: [uid] .
<Author.name>: string .
<BlogPost.content>: string .
<BlogPost.hasAuthor>: uid .
<BlogPost.title>: string .
<dgraph.drop.op>: string .
<dgraph.graphql.p_query>: string @index(sha256) .
<dgraph.graphql.schema>: string .
<dgraph.graphql.xid>: string @index(exact) @upsert .
: default .
type {
Author.name
Author.hasBlog
}
type {
BlogPost.title
BlogPost.content
BlogPost.hasAuthor
}
type <dgraph.graphql> {
dgraph.graphql.schema
dgraph.graphql.xid
}
type <dgraph.graphql.persisted_query> {
dgraph.graphql.p_query
}

GraphQL is more of an abstraction layer for interacting with your DB. Since you are interacting directly with DQL, those checks of GraphQL won’t apply (since you’re bypassing the GraphQL layer)

thanks for the swift reply. This starts making sense now.
Does that mean that DQL does not support non-nullable fields?

Yes that’s correct. DQL has weaker restrictions as compared to GraphQL

1 Like

PS. Just noticed it was answered few moments after writing this hehehe, but here it goes.

This has a very old version of Ratel. Please use latest or Dev.

You can, but you shouldn’t. As you are modeling your Graph using the GraphQL Schema, you should stick to the GraphQL model. Which means you have to always put the Type Prefix in all predicates.

It will execute cuz is its job :stuck_out_tongue:

Yes, in GraphQL context, not DQL.

Because there’s no “name” in the “Author” type, only “Author.name”. BTW, there is any reason that you are mixing GraphQL and DQL? Looks like you are a bit lost.

You can kind force it using strict

dgraph alpha -h | grep strict   
      --mutations string                 Set mutation mode to allow, disallow, or strict. (default "allow")

But it is not the same as GraphQL.