GraphQL - Core Concepts

November 1, 2021

Marcelo Amador

In the first part of this series, I started talking about GraphQL coming from 100% REST Api project.

Now, lets talk about some GraphQL core concepts that we will be using on the next part of this series.

Core Concepts

SDL (Schema Definition Language)

The syntax for writing schemas in GraphQL is called Schema Definition Language (SDL)

Here is an example based on the scenario we saw in the previous blog post


-- CODE language-js --
type Customer {
  name: String!
  age: Int!
}

This Customer type has two fields called 'name' as a string and 'age' as an integer. The '!' sign means that this field is required.

It is also possible to write relationship between types. Following our first blog post our 'Order' has a 'Customer':


-- CODE language-js --type Order {
  date: date!
  total: Float!
  delivered: Boolean!
  customer: Customer!
}

On the other hand, we also need to update our 'Customer' type that can have a list of 'Orders'


-- CODE language-js --type Person {
  name: String!
  age: Int!
  orders: [Order!]!
}

Fetching Data with Queries

When we fetch data with REST APIs, we have multiple endpoints, each one with a clearly defined structure of the returned information.

On GraphQL is very different. There's only a single endpoint that returns flexible data depending on what data the client needs. But at the same time, the client needs to send more information to the server to express which data is needed. This more information is called a Query

If we want a list of all Customers name, we can write a query like this:


-- CODE language-js --{
  allCustomers {
    name
  }
}

The 'allCustomer' on the query is called root field. Everything that follows the root field is called payload which in this case, we have only the field 'name'.

This query will return a list stored in database. Here's an example:


-- CODE language-js --{
  "allCustomers": [
    { "name": "Luke Skywalker" },
    { "name": "Lando Calrissian" },
    { "name": "Mace Windu" }
  ]
}

You might be asking where is the 'age' field we included when we created the 'Customer' type. Welcome to GraphQL!!! 😄. On the query we wrote to fetch customer data, we included only the 'name' field. If you want the 'age' as well, just update your query and the API side will still work without any update on it's side.

Updated query


-- CODE language-js --{
  allCustomers {
    name
    age
  }
}

Response from updated query


-- CODE language-js --{
  "allCustomers": [
    { 
      "name": "Luke Skywalker",
      "age": 33
    },
    { 
      "name": "Lando Calrissian",
      "age": 38
    },
    { 
      "name": "Mace Windu",
      "age": 144
    }
  ]
}

That's awesome! Now we can see the name and age.

But I still want more data. I want to see the Orders for each Customer.

A question for you: Do you need to make another API call to get Orders of each Customer you fetched?

The answer is: NO! Not in GraphQL.

We just need to make another update on our query. It would be like this:

New updated query


-- CODE language-js --{
  allCustomers {
    name
    age
    orders {
      date
      delivered
    }
  }
}

We included the 'orders' field from 'Customer' and we also selected the fields we want.

Fetch data with arguments

We can fetch data using arguments that was defined in the GraphQL schema.

For example, we include pass an argument to get only the last 2 customers


-- CODE language-js --{
  allCustomers(last: 2) {
    name
    age
  }
}

Making data changes with Mutations

Besides fetching data from a server, we might need to also create, update or delete data. On GraphQL, these operations are called Mutations.

Here's an example on how to create a new 'Customer'


-- CODE language-js --mutation {
  createCustomer(name:"Obi-Wan Kenobi", age: 189){
    name
    age
  }
}

On mutations, we have a root field - in this case, 'createCustomer' - and arguments - in this case, 'name' and 'age'.

Mutations also has a payload where we can specify which fields we want the 'createCustomer return to us.

The response from the mutation example above will be:


-- CODE language-js --"createCustomer": {
  "name":"Obi-Wan Kenobi",
  "age": 189
}

Realtime Updates with Subscriptions

If we want to have a realtime connection to the server in order to get immediately informed about important events, GraphQL has this concept of subscriptions

As mentioned on howtographql.com:


-- CODE language-js --When a client subscribes to an event, it will initiate and hold a steady connection to the server. Whenever that particular event then actually happens, the server pushes the corresponding data to the client. Unlike queries and mutations that follow a typical “request-response-cycle”, subscriptions represent a stream of data sent over to the client.

We can write Subscriptions using same syntax as queries and mutations. Here's an example where we subscribe to events happening on the 'Customer' type:


-- CODE language-js --subscription {
  newCustomer {
    name
    age
  }
}

After a client sent this subscription to the server, a connection is opened between them, and whenever a new mutation is performed that creates a new 'Customer', the server sends the information over to the client:


-- CODE language-js --{
  "newCustomer": {
    "name":"Han Solo",
    "age": 58
  }
}

Defining Schema

Now that we saw how to write queries, mutations and subscriptions on the client side, let's see how we define the respective schemas on the server side.

Generally, a schema is simply a collection of GraphQL types. However, when writing the schema for an API, there are some special root types:


-- CODE language-js --type Query { ... }
type Mutation { ... }
type Subscription { ... }

In this post, we wrote a query to fetch 'allCustomers'.

A schema for this query would be like this:


-- CODE language-js --type Query {
  allCustomers(last: Int): [Customer!]!
}

'allCustomers' is called the root field of the API. And between parenthesis, we can see the argument we included in the updated query to return only the last x customers. Similarly, for the 'createCustomer' mutation, we need to add the root field to the Mutation type:


-- CODE language-js --type Mutation {
  createCustomer(name: String!, age: Int!): Customer!
}

Note that the root field 'createCustomer' takes 2 arguments as well.

For our subscription, we need to add the 'newCustomer' root field:


-- CODE language-js --type Subscription {
  newCustomer: Customer!
}

What's next

This was a bit long post but I wanted to talk a bit of the GraphQL core concepts. It might be a bit overwhelming to read this much of information, but on the next chapter of this series, we will learn how to create a new Web API with GraphQL using .NET Core.

Again, all of this information, I summarize from howtographql.com.

See on the next series chapter.

Latest Posts

Let's Make Something Great Together

Contact Us

About Us