GraphQL - Core Concepts
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
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':
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'
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:
{
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:
{
"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
{
allCustomers {
name
age
}
}Response from updated query
{
"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
{
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
{
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'
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:
"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:
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:
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:
{
"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:
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:
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:
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:
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.