visit
Introduction
In this blog, I am not going to explain, why you should use GraphQL or when you should use GraphQL. Answering those questions requires architect level knowledge, which I don't possess at this very moment. I am just assuming, you have decided to use GraphQL in your project (either by force or by choice) and need a better understanding of it. As I have been using GraphQL recently, I have fallen into some common traps because of my lack of understanding of GraphQL. I don't want you to make the same mistakes. Having said that let's start our journey to understand what is GraphQL. We will learn about GraphQL and basic types for creating GraphQL schema in this blog.
GraphQL is a query language for your API, not for the database. It is database agnostic. It can be used with any database. GraphQL allows clients to query data from multiple sources in the API at one request and it allows clients to define which part of the data the client needed. Whilst providing you with such flexibility, GraphQL has some problems as well, for instance, the famous N+1 problem. Before we jump into that, let's discuss some common terminology used in GraphQL.
Schema
Schema is the blueprint for your GraphQL service. Before you can start using that, you have to define some schema using the GraphQL schema definition language. It has a very simple syntax for defining schema. Once you understand the basic terms and usage you will be able to create schemas in no time. During schema design, we define types and their requirements. We can Query the data from API using those types and perform Mutation on those types as well. So, what is a Query and a Mutation?
Query
As per the GraphQL documentation,
Every GraphQL service has a query type and may or may not have a mutation type. These types are the same as a regular object type, but they are special because they define the entry point of every GraphQL query.
When we send a request to a GraphQL service to query some data, we mention the type of data that we want in response and the necessary fields inside that type.Let's say you have a type called User and it has some fields like id, name, avatarLink, dateOfBirth, location, etc. When you want to show the users list in client-side, you only need the user's name and avatarLink. So you can perform a query as follows,
{
user {
name
avatarLink
}
}
And the response will look like,
{
'data': {
'user': {
'name': 'John Snow',
'avatarLink': '//....'
}
}
}
To define this query in the schema, we need to write,
type Query {
user(id: ID!): User
... # other query definition.
}
Here we have defined the Query type in our schema. That means, clients can query for a user by some id and in response, they will get the respective User object. The ! mark after ID means that id field is required. We can not query for a user without the id field. An explanation of what ID is or what User will be available in a future section. So in short, we can say that by defining the query type, we create a portal to get different data from the client-side. Remember that every schema must have a query type defined and/or a mutation type defined.
Mutation
The mutation is another important type of schema definition. If you want to modify some data in the data store of your service using GraphQL, you need to define a mutation type. You can consider this as a union of post/put/delete http request type. Whenever we want to create/update/delete data, we need to perform a mutation. A mutation can be defined as,
type Mutation {
createUser(name: String!, avatarLink: String, dateOfBirth: String, location: String): User
... # Other mutations
}
In the mutation above, we defined a mutation that will take a name, avatarLink, dateOfBirth, location as input, and then in response returns a User object. By now, you might already understand that the name field is a required parameters and other fields are not. We can send a mutation request from client side like this,
mutation {
createUser(name: 'Ned Stark') {
name
location
avatarLink
}
}
What you will get in response is something like this,
{
'data': {
'createUser': {
'name': 'Ned Stark',
'location': null,
'avatarLink': null,
}
}
}
Now as you understand the two most important types in GraphQL schema, let's get back to the understanding of schema. Schema is a definition of different types of data that is used throughout your application. You can think of it as the data model, for example, what your data are constructed with, which data a client can request or mutate. In order to define a type, we have some primary building blocks in GraphQL. They are called Scalar types. All complex types boil down to a Scalar at the end. There are 5 Scalar types by default in GraphQL. As per the they are,
Besides these scalar types, we can define our own Scalar types if needed. You can define custom scalars as follows:
scalar Date
How that type should be serialized, deserialized, and validated is up to your implementation. For example, you could specify that the Date type should always be serialized into an integer timestamp, and your client should know to expect that format for any date fields.
Enums: Enums are special type of Scalar. It has a very specific number of allowed values. We have to define those values during the definition of the Enums itself. For example:
enum PrivacyType {
Public
Private
}
If you define some field to be of PrivacyType, then you won't be able to set any values other than Public or Private for that field. We always expect the value to be either Public or Private.
So far, we have learned about GraphQL Schema definition language, basic types, mutation and query types. Now you will be able to create a basic schema with mutations and queries. In the next part we will learn how to create custom types and advanced feature of GraphQL, such as, Fragments, annotations, Union, Interface.
Leveraging these feature, you will be able to create a more complex schema. If you find any mistake in the above section or you have some suggestion feel free to share. Feedbacks are always welcome. You can contact me via , . You can also read this blog here.