Telerik blogs
JavascriptD_870

GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. In this post, we'll take an in-depth look at GraphQL core features like queries, mutations and subscriptions to better understand them and equally demonstrate how we can best leverage their functionality to build better APIs with GraphQL.

Queries

I consider queries to be the single most important part of the GraphQL architecture. They are the means by which the client can request the data it needs from the server.

GraphQL queries also provide the major difference between GraphQL and REST. As such, while REST has a clear structure of the data returned from a certain endpoint, GraphQL only exposes one endpoint for all requests, thus allowing the client to ask for what it specifically needs.

As is common in the GraphQL community, the structure of GraphQL queries makes it possible to uphold the common saying that, “With GraphQL, you can ask for what you want and get exactly that in return, no more, no less.” Consider the example below:

{
  Cars {
    model
  }
}

This is the basic composition of a simple query, a root field (in this case, Cars) which is the object containing the payload, and the payload itself (in this case, model) which is the field(s) requested by the client. Obviously, this query is asking the server for the model of the Cars so the response will look exactly like this:

{
  "Cars": [
    { "model": "Mercedez Benz E-Class" },
    { "model": "Toyota Camry" },
    { "model": "Toyota Corolla" },
    { "model": "Honda Accord" },
    { "model": "BMW" },
    { "model": "Peugeot" },
    { "model": "Ferrari" }
  ]
}

As expected, the server will respond with exactly the data that was requested. Because we only request for the model field, the server only responded with that data. Now, for instance, we redefine our query to ask for another field, year, like so:

{
  Cars {
    model
    year
  }
}

We'll get the new requested field in the response like so :

{
  "Cars": [
    { "model": "Mercedez Benz E-class", "year":"2012" },
    { "model": "Toyota Camry", "year":"2010" },
    { "model": "Toyota Corolla", "year":"2013" },
    { "model": "Honda Accord", "year":"2009" },
    { "model": "BMW", "year":"2010" },
    { "model": "Peugeot", "year":"2014" },
    { "model": "Ferrari", "year":"2015" },
  ]
}

There are other features that extend the abilities of GraphQL queries. For instance, we could use Arguments to return a specific car with its brand and even query for more data on the selected car. Consider this example:

{
  Car(brand: "Benz") {
    model
    year
    transmission
  }
}

Here we have passed an Argument to narrow down our request to a specific car with the name of the car brand, which in this case is “Benz.” Now the server will respond with all the fields we have requested on this car (which are model, year and transmission) like so:

{
  "car": { 
    "brand": "Benz", 
    "model": "Mercedez Benz E-class",
    "year" : "2012",
    "transmission" : "automatic"
  } 
}

You can also look up more features of GraphQL queries like Variables, Aliases, Operation Syntax, Fragments, Directives and so on to better understand the extent of queries.

Mutations

In GraphQL, mutations are mostly used to modify data on the server. They're not very different from the queries we've written before. As a matter of fact, they share the same syntax with the inclusion of the mutation keyword. With GraphQL mutation, we can Create, Update and Delete data on the server.

Create New Car

Considering our previous query examples, if we wanted to create or add a new car to our Cars, we can do so with mutation like this:

mutation {
  createCar(model: "Lamborgini", year: "2013") {
    model
    id
    year
  }
}

The mutation is defined just like a query. In our example above, the mutation has a root field and a payload just like our initial query definition. Notice that we have also passed three Arguments (model, id and year) with which we'll create the new car.

When creating new data (car), it is important to assign a unique identifier to the new car to make it easy to identify and perform operations on it. GraphQL has a simple approach to doing this — you can attach the GraphQL type ID to a field to automatically generate a unique ID for each new car object created, which is what we have done with the mutation above.

For our mutation to work, of course a GraphQL type called Car has to exist with the arguments we have passed to our mutation and the uniquely generated ID like so:

type Car {
  id: ID!
  model: String!
  year: String!
}

In the same way we create new cars, we can equally use a mutation to update and delete cars from our Cars record.

Subscriptions

So far, we have seen how to fetch data from the server using queries and how to modify data on the server with mutations. Next, let's look at how we can subscribe to events on the server with GraphQL subscriptions. According to the GraphQL documentation, subscriptions are a way to push data from the server to the clients that choose to listen to real-time messages from the server.

What this means is that with GraphQL subscriptions, we can create and maintain a real-time connection to the server. That way, we can subscribe to an event on the server, whenever that event is called, the server responds with corresponding data to the client in real time.

Just like queries, subscriptions specify a set of fields to be delivered to the client whenever an event happens on the server. The difference is, with queries, you get the requested data fields(s) you defined in the query in one answer when the request gets to the server, and that's it. With subscriptions, however, the connection remains open and sends a result to the client every time a particular event happens on the server.

Consider a situation in which we want to notify all our connected clients whenever a new car is created. We'll simply get updates from the server whenever the event happens and update the client automatically without having to make a separate request for it. Just like queries and mutations, GraphQL subscriptions also have to be defined in the schema:

type Subscription {
  newCarAdded(model: String!, year: String!): Car
}

Next we write the subscription query on the client:

subscription carAdded {
  carAdded {
    model
    year
  }
}

With this, we are now listening for the car addition event. Whenever a user adds a new car, a response will be sent to the client in this format:

{
  "data": {
    "carAdded": {
      "model": "the added car model",
      "year": "the added car year"
    }
  }
}

In the same vein, we can listen to a delete event, update event, etc. Kindly note that the code above only defines the GraphQL subscription in the schema. You can set up subscription on the client or on the server when adding it to your app.

Conclusion

In this post, we have tried to give you some insight into GraphQL features queries, mutations, and subscriptions. This is not nearly all you need to know about them — the scope is meant to give you a basic understanding of these features. Feel free to read more about them in the official documentation.

 

For More Info on Building Great Web Apps

Want to learn more about creating great web apps? It all starts out with Kendo UI - the complete UI component library that allows you to quickly build high-quality, responsive apps. It includes everything you need, from grids and charts to dropdowns and gauges.

Learn More about Kendo UI

Get a Free Trial of Kendo UI


About the Author

Christian Nwamba

Chris Nwamba is a Senior Developer Advocate at AWS focusing on AWS Amplify. He is also a teacher with years of experience building products and communities.

Comments

Comments are disabled in preview mode.