Simple Dgraph schema to GraphQL schema mapping doesn't work

Hi,

I’m trying to use the latest dgraph/dgraph:v20.07.0-beta.Jun22 to map an existing Dgraph schema to graphql schema and expose my database via graphql.

It didn’t work for me so I created this minimal example, which doesn’t work either.

In the ratel console I set these two nodes from the tutorial:

{
  "set": [
    {
      "name": "Karthic",
      "age": 28,
      "follows": {
        "name": "Jessica",
        "age": 31
      }
    }
  ]
}

I can query them in ratel:

{
  people(func: has(name)) {
    name
    age
  }
}

The result:

{
  "data": {
    "people": [
      {
        "name": "Karthic",
        "age": 28
      },
      {
        "name": "Jessica",
        "age": 31
      }
    ]
  },
  "extensions": {
	...
  }
}

Now I want to expose it via graphql so following the documentation at https://graphql.dgraph.io/dgraph/ I tried this:

curl localhost:8080/admin/schema -d '
type Person {
    name: String @search(by: [hash]) @dgraph(pred: "name")
    age: Int @dgraph(pred: "age")
    follows: Person @dgraph(pred: "follows")
}
'

I expected this to map to the implicit Dgraph schema generated after adding Karthic and Jessica to Dgraph previously. However, when I query via graphql I don’t get back these nodes:

curl 'http://localhost:8080/graphql' \
  -H 'Content-Type: application/json' \
  -H 'Accept: */*' \
  --data-binary '{"query":"query {\n  queryPerson {\n    name\n    age\n  }\n}","variables":null}'

Result:

{"data":{"queryPerson":[]},"extensions":{}}

Could you please help me what am I doing wrong here?

Thanks!

1 Like

It is missing it’s type on import using the set command.

It is missing the type. So you are creating 2 nodes and a total of 7 predicates (including understood uids) but when you define your graphql schema it is looking for types which you have not defined anywhere.

I am not sire the exact syntax for this JSON set command but it should be in the docs. Make sure you set the type to “Person”

The “set” command is not graphql in this case but GraphQL± and is executed in ratel. Creating these nodes in ratel I wanted to simulate an “existing” database, ie. one that has been created without knowing about graphql.

Then having this “existing database” I try to expose it es graphql, therefore following the docs I try to “attach” a grpahql schema via localhost:8080/admin/schema. As per the docs, this should work.

Right, I understand. I did almost the same thing but I used triples instead of JSON with the set command that gets queried by graphql endpoints.

Here is my untested attempt:

{
  "set": [
    {
      "dgraph.type" : "Person",
      "Person.name": "Karthic",
      "Person.age": 28,
      "Person.follows": {
        "dgraph.type": "Person"
        "Person.name": "Jessica",
        "Person.age": 31
      }
    }
  ]
}

This in triple format would look like:

{
  set {
    _:person1 <dgraph.type> "Person" .
    _:person1 <Person.name> "Karthic" .
    _:person1 <Person.age> "28" .
    _:person1 <Person.follows> _:person2 .
    _:person2 <dgraph.type> "Person" .
    _:person2 <Person.name> "Jessica" .
    _:person2 <Person.age> "31" .
  }
}

You can learn more at https://graphql.dgraph.io/dgraph

Pay attention to the types.

It is possible to map graphql schema to align to Dgraph schema in the last part of that doc page.

2 Likes

Thank you very much for your example! You are right, with explicit typing it works. I tried with your example:

{
  "set": [
    {
      "dgraph.type" : "Person",
      "Person.name": "Karthic",
      "Person.age": 28,
      "Person.follows": {
        "dgraph.type": "Person",
        "Person.name": "Jessica",
        "Person.age": 31
      }
    }
  ]
}
curl localhost:8080/admin/schema -d '
type Person {
    name: String @search(by: [hash])
    age: Int
    follows: Person
}
'
query {
  queryPerson {
    name
    age
  }
}
{
  "data": {
    "queryPerson": [
      {
        "name": "Karthic",
        "age": 28
      },
      {
        "name": "Jessica",
        "age": 31
      }
    ]
  },
  "extensions": {
    "touched_uids": 6
  }
}

However, my actual database where I want to try graphql doesn’t have such typing. That’s why I tried to achieve the mapping using @dgraph as suggested by the documentation and also by you as a way to align a graphql schema to an existing drgaph schema.

So I feel there’s still something missing here …

I missed that in your OP. sorry.

So, from my understanding, using the @dgraph mapping will take care of not needing the Type.field in Dgraph schema, but you still need the node type.

Try this:

{
  "set": [
    {
      "dgraph.type": "Person",
      "name": "Karthic",
      "age": 28,
      "follows": {
        "dgraph.type": "Person",
        "name": "Jessica",
        "age": 31
      }
    }
  ]
}

If you already have existing schema and data, you will need to apply types to the nodes themselves but you can leave the existing predicates alone. You could follow the Bulk Upsert Exampled here to achieve this:

upsert {
  query {
    v as var(func: has(name)) { # a filter to find the nodes that should be a Person
      getValues as name #we won't be using this part...
    }
  }

  mutation {
    set {
       uid(v) <dgraph.type> "Person" .
    }
  }
}

Of course you would have to be careful with your filter to make sure that it only gets Person types. An instance where this would not work very well is if your schema uses many of the same predicates for different types (ie: If you have other nodes with name and age is an optional predicate then the only way to set the dgraph.type would be through listing the specific uids that need to be that type.

2 Likes

OK, so it seems we always need Dgraph typing (<dgraph.type>) in order to be able to map to graphql, right?

In this case the documentation at https://graphql.dgraph.io/dgraph is not correct or @dgraph doesn’t work. Do you think I should submit an issue about it?

I also tried your example, unfortunately I got this error for the upsert:

{
  "name": "t",
  "url": "http://localhost:8080/mutate?commitNow=true",
  "errors": [
    {
      "message": "Some variables are defined but not used\nDefined:[getValues v]\nUsed:[v]\n",
      "extensions": {
        "code": "ErrorInvalidRequest"
      }
    }
  ]
}

It seems to be related to this issue:

Nevertheless, thanks for your help!

When you use @dgraph directive the expectation is that you will be adding data through GraphQL layer hence dgraph,type will be automatically added.

1 Like

My apologies remove the getValues as from my code example above.