- Return just what is required in the client, avoid underfetching and overfetching;
- One endpoint, allows rapid front-end iterations (no need to wait for endpoints being added/modified);
// operations: Query, Mutation, Subscription
type Query {
allPersons(last: Int): [Person!]!
allPosts(last: Int): [Post!]!
}
type Mutation {
createPerson(name: String!, age: Int!): Person!
updatePerson(id: ID!, name: String!, age: Int!): Person!
deletePerson(id: ID!): Person!
createPost(title: String!): Post!
updatePost(id: ID!, title: String!): Post!
deletePost(id: ID!): Post!
}
type Subscription {
newPerson: Person!
updatedPerson: Person!
deletedPerson: Person!
newPost: Post!
updatedPost: Post!
deletedPost: Post!
}
// actual entities: one to many relation between Person and Post
type Person {
name: String!
age: Int!
posts: [Post!]!
}
type Post {
title: String!
author: Person!
}
!
indicates a required field;[Foo]
a list ofFoo
;
- A field can be of a scalar or composite type;
- Scalar types include:
Int
,Float
,String
,Boolean
; - A composite type:
type Post { title: String! author: Person! }
- Scalar types include:
Last 2 persons, getting name
and age
:
{
allPerson(last: 2) {
name
age
}
}
# it's a good practice to add in operation type and name
query GetLatestTwoPersons {
allPerson(last: 2) {
name
age
}
}
query GetLatestPersons($count: Int!) {
allPerson(last: $count) {
name
age
}
}
{
"count": 2
}
query GetLatestPersons($count: Int!, $includeAge: Boolean!) {
allPerson(last: $count) {
name
age @include(if: $includeAge)
}
}
{
"count": 2,
"includeAge": true
}
Another common directive is @skip
, the logic is inversed.
query GetLatestTwoPersons {
allPerson(last: 2) {
fullname: name # use 'fullname' as an alias of 'name'
age
}
}
# you can have multiple aliases for the same field/query
query GetLatestPersons {
last2: allPerson(last: 2) {
name
age
}
last3: allPerson(last: 3) {
name
age
}
}
query GetLatestPersons {
last2: allPerson(last: 2) {
...PersonInfo
}
last3: allPerson(last: 3) {
...PersonInfo
}
}
fragment PersonInfo on Person {
name
age
}
query GetShapes {
shape {
... on Circle {
radius
}
... on Rectangular {
width
length
}
}
}
Here shape
has a union type: either a Circle
or a Rectangular
- All mutation queries starts with the
mutation
keyword; - Allows you to mutate and query with the same query;
mutation {
createPerson(name: "Bob", age: 36) {
name
age
}
}
subscription {
newPerson {
name
age
}
}