-
Notifications
You must be signed in to change notification settings - Fork 4
Schema Conventions
GraphSchema uses some simple conventions to work out what to do by default.
This description is based on the example here, which contains most of what GraphSchema can accept.
In general, you write a schema with the types you want, and the mutations and queries you want the endpoint to expose. GraphSchema then interprets that to work out how to handle any particular query.
- Valid GraphQL types, enums, references, lists and nullable/not-null should be ok.
- GraphQL scalar types int, float, string and boolean are accepted
- GraphSchema also accepts a
DateTime
scalar type (maps to dgraphdatetime
type) - A type can have at most one
ID
field, which can't appear on the corresponding input type. (at the moment this maps to Dgraph UID, but soon GraphSchema will allow ID's to be input and GraphSchema will ensure uniqueness: e.g. user names)
E.G.
type Post {
id: ID!
title: String
text: String
author: Author!
postedAt: DateTime!
postType: PostType!
}
...
enum PostType {
Question
Answer
...
}
A type T
can have a corresponding input type TInput
that has a subset of the type's fields.
E.G
input PostInput {
title: String
text: String
author: Author
}
or
input PostInput {
title: String
text: String
author: Author
postedAt: DateTime!
postType: PostType!
}
The ID field can't appear in the input type
Any type T
can have a mutation called addT
. The mutation must have a single argument of type TInput
.
E.G
type Mutation {
...
AddPost(inputData: PostInput!): Post
}
Running the mutation will add a new record of type T
and return it.
Limitations :
- currently links to existing data must be supplied as a uid in the input: e.g the input for a post should have
{ "input": { ..., "author": { "uid": "0x2" } }}
. This will change to the actual field name soon.
Three query types are currently supported:
- get: get an individual by Id
- query: query the type using Dgraph query functions
- query via given translation
A type T
can have a query getT
that must take an input called id
of ID
type and return a T!
E.G.
type Query {
...
GetPost(id: ID!): Post!
...
}
This will search the store by both ID and expected type to find the matching data.
A type T
can have a query queryT
that may take an argument func
of type String
and returns a list of T
E.G.
type Query {
...
QueryAuthor(func: String): [Author!]!
...
}
A query like queryAuthor { ... }
that doesn't include the argument will find every author.
A query like queryAuthor(func: "some function") { ... }
, or queryAuthor(func: $varName)
for a variable, must take input of a string that's a legal Dgraph query functions.
E.G.
queryAuthor(func: "lt(birthday, \"1980-01-01\")") { ... }
queryPost(func: "anyofterms(title, \"GraphQL\")") { ... }
The Dgraph rules about indexes apply.
As well as the queries translated by convention above, GraphSchema also allows to set a translation for a query.
E.G.
type Query {
...
MostLikedPost(query: String!): Post
...
}
and annotation
# [GraphSchema/Dgraph] MostLikedPost -> GraphSchema.Translation.MostLikedPost
tells GraphSchema to use the file GraphSchema.Translation.MostLikedPost
to help translate the query.
The translation file is part of a Dgraph query (minus the external braces), that must have a
mostLikedPost as var ...
as its final result. GraphSchema will wrap that in the variables definitions passed into the query as well as a query result that extracts the result. E.G
query mostliked($query: String!) { <-- GraphQL variable definitions
...
mostLikedPost as... <-- translation file inserted
mostLikedPost((func: uid(mostLikedPost))... <-- translation of GraphQL inserted here
}
because of this translation the variable names in the translation file and the GraphQL query must match (e.g. both $query in this case).
If the schema contains the directives
directive @filter(filter: String!) on FIELD
directive @paging(paging: String!) on FIELD
directive @order(order: String!) on FIELD
Then those can be used to filter and page.
E.G.
queryPost(func: $inp) @paging(paging: "first: 1") { ... }
To get the first matching post.
or
query getAuthor {
getAuthor(id: "0x2") {
id,
name,
posts @filter(filter: "anyofterms(title, \"API\")") { title }
}
}
To insert a search filter into a query.
As well as picking up any conventions listed above, GraphSchema uses annotations at the end of a schema file to add further information.
The end of a schema file can have a section
### GraphSchema
# [GraphSchema] author INV posts
# [GraphSchema/Dgraph] Post . text @index(fulltext)
...
Use # [GraphSchema/Dgraph] Post . text @index(fulltext)
to place a Dgraph index on fields you wish to search over.
Annotation # [GraphSchema] author INV posts
specifies that edges author and post are inverses of each other. In this case, GraphSchema will automatically fill in the posts: [Post!]!
field on author from the AddPost mutaions (so posts shouldn't be in the input type).
Annotation # [GraphSchema] ApiKeys
enforces API keys for all access to the API - see Security
If an input type is annotated as
# [GraphSchema] AuthorInput . password -> Secret
GraphSchema creates the corresponding type (Author
) with a Dgraph password
type edge. GraphSchema will expect a password in the input type which is passed through to Dgraph, encrypted and stored. The query type is then permitted to check the password by extending the get type
type Query {
GetAuthor(id: ID!, secret: String): Author
...
}
A get with the correct Id and password will return the corresponding record. An incorrect pair returns null.
Because secrets are stored encrypted, once stored they can't be retrieved, only checked against with a get.
(Once the ID type is extended to things other than Dgraph uid (e.g. usernames) this allows, for example, easy login checking.)
- Modifications
- Delete semantics