Query
You write queries to retrieve data (specific fields on objects). The syntax, it's not JSON, is specified here.
Query
A query is a read-only operation and has the following syntax:query [name] [variables] [directives] selection
.
Note: []
means optional. A very simple query might look like this:
query {
hello
courseInstructor
}
and might return a JSON object like this:
{
"data": {
"hello": "Hello world!",
"courseInstructor": "Andrew Mead"
}
}
So as you can see, the request structure dictates the response.
You can use this playground to see for yourself.
On the right-hand side you can see the Schema menu, which shows you which queries you can create.
GraphQL is self-documented by default which makes it super easy to consume. When there is an exclamation mark !
behind a type, then you will always get back this field (kinda like required), otherwise it might be null
(optional field).
Query an Object
When you query an object you always have to specify which fields you want to query. It is not possible to get all fields back when just specifying the name of the object or array of objects (non-scalar type). Example:
query {
hello
courseInstructor
me {
name
}
}
Response:
{
"data": {
"hello": "Hello world!",
"courseInstructor": "Andrew Mead",
"me": {
"name": "Andrew"
}
}
}
Query an Array
If you see the return type in brackets ([]
), then it means you will get back an array of data.
Also in this case you have to specify which field each item of the array must contain.
Example:
query {
hello
courseInstructor
users {
name
}
}
Response:
{
"data": {
"hello": "Hello world!",
"courseInstructor": "Andrew Mead",
"users": [
{
"name": "Andrew"
},
{
"name": "Sarah"
},
{
"name": "Michael"
}
]
}
}
Operation Arguments
You can pass a query arguments. On the server side you would have something like this:
Query {
greeting(name: String): String!
}
Resolver {
greeting(name: string) {
return `Hello ${name}`;
}
}
On the client side you can pass the argument as follows:
query {
greeting(name: "Tom")
}
Relational Data
As our data is kept as a graph we can easily navigate relations. E.g. a type User
can be the author
of a Post
.
To get the author of a post we need to connect the post with the user.
type Query {
posts: [Post]!
}
type User {
id: ID!
name: String!
}
type Post {
id: ID!
title: String!
author: User!
}
The author property in the post would contain the ID of the user. Now in our resolver we need to provide the link from a post to the user, a custom resolver function, as follows:
Query {
posts() { ... }
}
Post {
author(parent) { // parent is a post object, so we can access all the fields from post in here
return users.find(user => user.id === parent.author)
}
}
For the other way around, e.g. get all posts of a user we would have to provide this custom resolver function:
Query {
users() { ... }
}
User {
posts(parent) { // parent is a user object, so we can access all the fields from post in here
return posts.filter(post => post.author === parent.id)
}
}