In this post, we have discussed the core GraphQL concepts e.g. schema, types, queries, mutations, and subscriptions with example codes.
Core Concepts of GraphQL
- Schema
- Types
- Queries
- Mutations
- Subscriptions
- Resolvers
Scheme
- The schema defines how a client can read and manipulate (add, update, and delete) data
- It represents a contract between client and server
- It consists of GraphQL types and the special root types
- Root types define the entry points for the API (type Query, type Mutation, type Subscription)
Types
- GraphQL provides schema definition language (SDL) to define simple types
- Types define the structure of the data and how the data is manipulated
- GraphQL allows creating relationships between types
Example Code
//User type
type User{
id: ID!
name: String!
courses: [Course!]!
}
//Course type
type Course{
id: ID!
title: String!
url: String
author: User!
}
// ! indicates that the field is required
// One to many relationship is defined between User and Course //types
Queries
- Queries are used to fetch (read) data from GraphQL API
- A query specifically describes what data it needs in the response
- Arguments are passed in the queries to return/alter data based on the arguments
- Queries can be used to get nested or relational data as well
Example Code
type Query{
getCourses(last: Int): [Course!]!
}
//get all courses with only title field
{
courses: {
title
}
}
//get all courses with author info i.e. name
{
courses: {
title
author: {
name
}
}
}
Mutations
- Mutations are used to modify data i.e. create, update or delete
- Mutations accept arguments (input) and payload (expected output)
Example Code
type Mutation {
addUser(name: String!): User
!
}
mutation {
addUser (name: "junaid", courses: []) {
id
name
}
}
Subscriptions
- GraphQL subscriptions provide real-time updates to the subscribers
- Whenever new data is added, the subscriptions notified or pushes the data back to the subscriber in real-time
type Subscription{
addUser: User!
}
subscription {
newUser{
id
name
}
}
Resolvers
- For each query and mutation, there is a resolver function with the same name as the query or mutation
- The resolver function communicates with the appropriate data source and sends the response
//import Course from "../../models/Course"; mongoose model
Query: {
async allCourses() {
try {
const courses = await Course.find();
return courses;
} catch (err) {
throw new Error(err);
}
}
},
Mutation: {
async addCourse(parent, { name, url }, context, info) {
try {
const course = await new Course({name, url});
return course.save();
} catch (err) {
throw new Error(err);
}
}
}