Categories
GraphQL

Introduction to GraphQL Schemas and Types

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at the GraphQL type system and how it describes what data can be queried.

Schemas and Types

GraphQL requests are about selecting fields on objects.

In a query, we have a root object, then we select a field from that and fields below that level if it exists all the way to the bottom level.

For example, if we have the query:

{
  person {
    name
  }
}

Then we get something like:

{
  "data": {
    "person": {
      "name": "Jane"
    }
  }
}

as the response.

A GraphQL query closely matches the result so we can predict what the query will return without knowing that much about the serve.

But it’s still useful to have an exact description of data we can ask for.

This is where explicit types are useful.

Type language

GraphQL services can be written in any language. Therefore, types have to be defined in a language-agnostic way.

Object types and fields

We can define a GraphQL data type as follows:

type Person {
  name: String!
  addresses: [Address!]!
}

In the code above, we created a new type with the type keyword. In the type, we have the name field, which is String , and addresses , which is an array of Address es, which is another type.

String is a built-in scalar type. The exclamation marks mean the field is not nullable. Therefore, String! is a non-nullable string.

[Address!]! is an array of Address objects. It’s also non-nullable, so we can always expect an array with zero or more items when we query for addresses . Since Address! is also non-nullable, we can always expect every item of the array to be an Address object.

Arguments

Every field of a GraphQL object type can have zero or more arguments.

For example, we can write the following:

type Person {
  name: String!
  height(unit: HeightUnit = METER): Float
}

In the code above, we have the height field in the Person that takes a unit as the argument. unit is of type HeightUnit which is set to METER by default.

height returns a Float.

The Query and Mutation types

There’re 2 types that are special within a schema. They’re Query and Mutation .

Every GraphQL service has a query type and may or may not have an mutation type.

These types are the same as any other object type, but they’re special because they define the entry point of every GraphQL query.

If we have a query like the following:

query {
  person {
    name
  }
  robot(id: "2000") {
    name
  }
}

Then the GraphQL service needs to have the query type with the person and robot fields:

type Query {
  person(name: String): Person
  robot(id: ID!): Robot
}

We define mutation types the same way. We define fields on the Mutation type and those are available as the root mutation fields we can call in our query.

Scalar types

Scalar fields are what all object types contain in the end. They’re the most basic types of fields.

GraphQL comes with the following scalar types out of the box:

  • Int — a signed 32-bit integer
  • Float — a signed double-precision floating-point value
  • String — a UTF-8 character sequence
  • Boolean — true or false
  • ID — a unique identifier that used for fetching an object or as the key for a cache. It’s serialized the same way as a String but it’s not intended to be human-readable

Most GraphQL service implementations also let us specify custom scalar types.

We can define one as follows:

scalar Date

Then it’s up to use to decide how to serialize, deserialize and validate them.

Enumeration types

Enum types are special types of scalar that are restricted to a particular set of allowed values.

It lets us validate that any argument of the type is one of the allowed values.

Also, it communicates through the type system that a field will always be one of a finite set of values.

We can define an enum as follows:

enum Fruit {
  APPLE
  ORANGE
  GRAPE
}

Then if we have Fruit , we expect it to be either APPLE, ORANGE or GRAPE .

Conclusion

We can define types so that we can validate the data that’s submitted to the GraphQL server.

To do this, we create a type with the type keyword if it’s an object type.

We can also create scalar types which are the most basic types that can be included in other types or referenced directly. We can define them with the scalar keyword.

To define a type with fixed values, we can define an enum type with a few possible constant values.

The exclamation mark indicates that a type is not nullable.

Categories
GraphQL

Introduction to GraphQL — Variables and Complex Operations

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at more complex GraphQL operations, including passing in variables, directives, mutations, and more.

Variables

In most apps, the arguments for queries need to be dynamic. It wouldn’t be a good idea to pass in dynamic arguments directly to the query string.

Fortunately, GraphQL lets us pass in variables into our operations request.

For example, we can write:

query PersonName($id: Int) {
  person(id: $id) {
    name
  }
}

to pass in an $id variable into our person query.

Then we can pass in variables via an object to make the request:

{
  "id": 1000
}

Then we get something like:

{
  "data": {
    "person": {
      "name": "Jane"
    }
  }
}

as the response.

Variable definitions

Variable definitions start with the variable name prefixed with a $ , then the type of the variable.

In the example above, we have $id as the variable name and Int as the type.

All declared variables must be either a scalar, enums or other input object types.

If we want to pass a complex object into a field, we need to know the input type to match on the server.

Default variables

We can set default values for variables as follows:

query PersonName($id: Int = 1) {
  person(id: $id) {
    name
  }
}

In the code above, we added = 1 after $id: Int to set the default value for $id to 1.

Directives

We can use directives to dynamically change the structure and shape of our queries using variables.

For example, we can include directives as follows to make our query dynamic:

query Person($id: Int, $withFriends: Boolean!) {
  person(id: $id) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

In the code above, we have the @include(if: $withFriends) directive to conditionally includes friends if $withFriends is true.

Therefore, if we make the following query with the following variables:

{
  "id": 1000,
  "withFriends": false
}

Then we may get something like:

{
  "data": {
    "person": {
      "name": "Jane"
    }
  }
}

as a response.

A directive can be attached to a field or fragment inclusion and can affect the execution of the query in any way the server desires.

The core GraphQL specification includes 2 directives that must be supported by any spec-compliant GraphQL server implementation:

  • @include(if: Boolean) — only include this field if the argument if true.
  • @skip(if: Boolean) — skip this field if the argument is true.

It helps us get out of situations where we would have to do string manipulating to add and remove fields in our query.

Mutations

We can use mutations to send requests to change data on the server.

They’re similar to queries, except that it starts with the keyword mutation instead.

For example, we can define a mutation as follows:

mutation CreatePerson($firstName: String, $lastName: String) {
  createPerson(firstName: $firstName, lastName: $lastName) {
    firstName
    lastName
  }
}

Then if we make the following query:

{
  "firstName": "Joe",
  "lastName": "Smith"
}

we may get the following response:

{
  "data": {
    "createPerson": {
      "firstName": "Joe",
      "lastName": "Smith"
    }
  }
}

In the response, we return the firstName and lastName fields as we specified in the request.

A mutation can contain multiple fields like a query. Mutations fields run in series.

This means that if we sent 2 createPerson mutations in one request. The first will finish before the second begins.

Inline Fragments

We can define interface and union types with GraphQL requests.

To do this, we use inline fragments to access data on the underlying concrete type.

For example, we can write the following query:

query Thing($id: Int!) {
  person(id: $id) {
    name
    ... on Person{
      gender
    }
    ... on Robot{
      memory
    }
  }
}

In the query above, the ...on operator indicates that we include an inline fragment within our query, where Person and Robot are our fragments.

Named fragments can also be inline fragments since they have a type attached.

Meta fields

We can request a __typename field to get the type of the data returned in the response.

For example, if we have the following query:

{
  search(text: "an") {
    __typename
    ... on Human {
      name
    }
    ... on Robot {
      name
    }
  }
}

Then we may get the following response from the server:

{
  "data": {
    "search": [
      {
        "__typename": "Human",
        "name": "Hans"
      },
      {
        "__typename": "Robot",
        "name": "Jane"
      }
    ]
  }
}

Conclusion

We can define mutations to make requests to change data.

To make requests dynamic, we can use variables to include variable data and directives for conditional inclusion of data in our response.

We can also use inline fragments for union types and include the type of data returned in the response by including the __typename property.

Categories
GraphQL

An Introduction to GraphQL

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at how to make basic queries to a GraphQL API.

Defining the API

We define an API by defining the types and fields for those types and provide functions for each field on each type.

For example, if we have the following type:

type Query {
  person: Person
}

Then we have to create a function for the corresponding type to return the data:

function Query_person(request) {
  return request.person;
}

Making Queries

Once we have a GraphQL service running, we can send GraphQL queries to validate and execute on the server.

For example, we can make a query as follows:

{
  person {
    firstName
  }
}

Then we may get JSON like the following:

{
  "person": {
    "firstName": "Joe"
  }
}

Queries and Mutations

Queries are for getting data from the GraphQL server and mutations are used for manipulating data stored on the server.

For example, the following is a query to get a person’s name:

{
  person {
    name
  }
}

Then we may get the following JSON from the server:

{
  "data": {
    "person": {
      "name": "Joe"
    }
  }
}

The field name returns a String type.

We can change the query as we wish if we want to get more data. For example, if we write the following query:

{
  person {
    name
    friends {
      name
    }
  }
}

Then we may get something like the following as a response:

{
  "data": {
    "person": {
      "name": "Joe",
      "friends": [
        {
          "name": "Jane"
        },
        {
          "name": "John"
        }
      ]
    }
  }
}

The example above has friends being an array. They look the same from the query perspectively, but the server knows what to return based on the type specified.

Arguments

We can pass in arguments to queries and mutations. We can do a lot more with queries if we pass in arguments to it.

For example, we can pass in an argument as follows:

{
  person(id: "1000") {
    name
  }
}

Then we get something like:

{
  "data": {
    "person": {
      "name": "Luke"
    }
  }
}

from the server.

With GraphQL, we can pass in arguments to nested objects. For example, we can write:

{
  person(id: "1000") {
    name
    height(unit: METER)
  }
}

Then we may get the following response:

{
  "data": {
    "person": {
      "name": "Luke",
      "height": 1.9
    }
  }
}

In the example, the height field has a unit which is an enum type that represents a finite set of values.

unit may either be METER or FOOT.

Photo by Giorgio Tomassetti on Unsplash

Fragments

We can define fragments to let us reuse complex queries.

For example, we can define a fragment and use it as follows:

{
  leftComparison: person(episode: FOO) {
    ...comparisonFields
  }
  rightComparison: person(episode: BAR) {
    ...comparisonFields
  }
}
​
fragment comparisonFields on Character {
  name
  appearsIn
  friends {
    name
  }
}

In the code above, we defined the comparisonFields fragment which has the list of fields we want to include in each query.

Then we have the leftComparison and rightComparison queries which include the fields of the comparisonFields fragment by using the ... operator.

Then we get something like:

{
  "data": {
    "leftComparison": {
      "name": "Luke",
      "appearsIn": [
        "FOO",
        "BAR"
      ],
      "friends": [
        {
          "name": "Jane"
        },
        {
          "name": "John"
        }
      ]
    },
    "rightComparison": {
      "name": "Mary",
      "appearsIn": [
        "FOO",
        "BAR"
      ],
      "friends": [
        {
          "name": "Mary"
        },
        {
          "name": "Alex"
        }
      ]
    }
  }
}

Using variables inside fragments

We can pass in variables into fragments as follows:

query PersonComparison($first: Int = 3){
  leftComparison: person(episode: FOO) {
    ...comparisonFields
  }
  rightComparison: person(episode: BAR) {
    ...comparisonFields
  }
}
​
fragment comparisonFields on Character {
  name
  appearsIn
  friends(first: $first) {
    name
  }
}

Then we may get something like:

{
  "data": {
    "leftComparison": {
      "name": "Luke",
      "appearsIn": [
        "FOO",
        "BAR"
      ],
      "friends": [
        {
          "name": "Jane"
        },
        {
          "name": "John"
        }
      ]
    },
    "rightComparison": {
      "name": "Mary",
      "appearsIn": [
        "FOO",
        "BAR"
      ],
      "friends": [
        {
          "name": "Mary"
        },
        {
          "name": "Alex"
        }
      ]
    }
  }
}

as a response.

The operation type may either be a query, mutation, or subscription and describes what operator we’re intending to do. It’s required unless we’re using the query shorthand syntax. In that case, we can’t supply a name or variable definition for our operation.

The operation name is a meaningful and explicit name for our operation. It’s required in multi-operation documents. But its use is encouraged because it’s helpful for debugging and server-side logging.

It’s easy to identify the operation with a name.

Conclusion

GraphQL is a query language that lets us send requests to a server in a clear way. It works by sending nested objects with operation type and name along with any variables to the server.

Then the server will return us the response that we’re looking for.

Operation types include queries for getting data and mutations for making changes to data on the server.

Categories
GraphQL Vue

How To Use GraphQL APIs in Vue.js Apps

GraphQL is a query language made by Facebook for sending requests over the internet. It uses its own query but still sends data over HTTP. It uses one endpoint only for sending data.

The benefits of using GraphQL include being able to specify data types for the data fields you are sending and being able to specify the types of data fields that are returned.

The syntax is easy to understand, and it is simple. The data are still returned in JSON for easy access and manipulation. This is why GraphQL has been gaining traction in recent years.

GraphQL requests are still HTTP requests. However, you are always sending and getting data over one endpoint. Usually, this is the graphql endpoint. All requests are POST requests, no matter if you are getting, manipulating, or deleting data.

To distinguish between getting and manipulating data, GraphQL requests can be classified as queries and mutations. Below is one example of a GraphQL request:

{
  getPhotos(page: 1) {
    photos {
      id
      fileLocation
      description
      tags
    }
    page
    totalPhotos
  }
}

In this story, we will build a Vue.js app that uses the GraphQL Jobs API located at https://graphql.jobs /to display jobs data. To start building the app, we first install the Vue CLI by running npm i @vue/cli. We need the latest version of Node.js LTS installed. After that, we run vue create jobs-app to create new Vue.js project files for our app.

Then, we install some libraries we need for our app, which include a GraphQL client, Vue Material, and VeeValidate for form validation. We run:

npm i vue-apollo vue-material vee-validate@2.2.14 graphql-tag

This installs the packages. Vue Apollo is the GraphQL client, and graphQL-tag converts GraphQL query strings into queries that are usable by Vue Apollo.

Next, we are ready to write some code. First, we write some helper code for our components. We add a mixin for making the GraphQL queries to the Jobs API. Create a new folder called mixins, and add a file called jobMixins.js to it. Then in the file, we add:

import { gql } from "apollo-boost";

export const jobsMixin = {
  methods: {
    getJobs(type) {
      const getJobs = gql`
      query jobs(
          $input: JobsInput,
        ){
          jobs(
            input: $input
          ) {
            id,
            title,
            slug,
            commitment {
              id,
              title,
              slug
            },
            cities {
              name
            },
            countries {
              name
            },
            remotes {
              name
            },
            description,
            applyUrl,
            company {
              name
            }
          }
        }
      `;
      return this.$apollo.query({
        query: getJobs,
        variables: {
          type
        }
      });
    },

    getCompanies() {
      const getCompanies = gql`
      query companies{
          companies {
            id,
            name,
            slug,
            websiteUrl,
            logoUrl,
            twitter,
            jobs {
              id,
              title
            }
          }
        }
      `;
      return this.$apollo.query({
        query: getCompanies
      });
    }
  }
}

These functions will get the data we require from the GraphQL Jobs API. The gql in front of the string is a tag. A tag is an expression, which is usually a function that is run to map a string into something else.

In this case, it will map the GraphQL query string into a query object that can be used by the Apollo client.

this.$apollo is provided by the Vue Apollo library. It is available since we will include it in main.js.

Next, in the view folder, we create a file called Companies.vue, and we add:

<template>
  <div class="home">
    <div class="center">
      <h1>Companies</h1>
    </div>
    <md-card md-with-hover v-for="c in companies" :key="c.id">
      <md-card-header>
        <div class="md-title">
          <img :src="c.logoUrl" class="logo" />
          {{c.name}}
        </div>
        <div class="md-subhead">
          <a :href="c.websiteUrl">Link</a>
        </div>
        <div class="md-subhead">Twitter: {{c.twitter}}</div>
      </md-card-header>

<md-card-content>
        <md-list>
          <md-list-item>
            <h2>Jobs</h2>
          </md-list-item>
          <md-list-item v-for="j in c.jobs" :key="j.id">{{j.title}}</md-list-item>
        </md-list>
      </md-card-content>
    </md-card>
  </div>
</template>

<script>
import { jobsMixin } from "../mixins/jobsMixin";
import { photosUrl } from "../helpers/exports";

export default {
  name: "home",
  mixins: [jobsMixin],
  computed: {
    isFormDirty() {
      return Object.keys(this.fields).some(key => this.fields[key].dirty);
    }
  },
  async beforeMount() {
    const response = await this.getCompanies();
    this.companies = response.data.companies;
  },
  data() {
    return {
      companies: []
    };
  },
  methods: {}
};
</script>

<style lang="scss" scoped>
.logo {
  width: 20px;
}

.md-card-header {
  padding: 5px 34px;
}
</style>

It uses the mixin function that we created to get the companies’ data and displays it to the user.

In Home.vue, we replace the existing code with the following:

<template>
  <div class="home">
    <div class="center">
      <h1>Home</h1>
    </div>
    <form [@submit](http://twitter.com/submit "Twitter profile for @submit")="search" novalidate>
      <md-field :class="{ 'md-invalid': errors.has('term') }">
        <label for="term">Search</label>
        <md-input type="text" name="term" v-model="searchData.type" v-validate="'required'"></md-input>
        <span class="md-error" v-if="errors.has('term')">{{errors.first('term')}}</span>
      </md-field>

      <md-button class="md-raised" type="submit">Search</md-button>
    </form>
    <br />
    <md-card md-with-hover v-for="j in jobs" :key="j.id">
      <md-card-header>
        <div class="md-title">{{j.title}}</div>
        <div class="md-subhead">{{j.company.name}}</div>
        <div class="md-subhead">{{j.commitment.title}}</div>
        <div class="md-subhead">Cities: {{j.cities.map(c=>c.name).join(', ')}}</div>
      </md-card-header>

      <md-card-content>
        <p>{{j.description}}</p>
      </md-card-content>

<md-card-actions>
        <md-button v-on:click.stop.prevent="goTo(j.applyUrl)">Apply</md-button>
      </md-card-actions>
    </md-card>
  </div>
</template>

<script>
import { jobsMixin } from "../mixins/jobsMixin";
import { photosUrl } from "../helpers/exports";

export default {
  name: "home",
  mixins: [jobsMixin],
  computed: {
    isFormDirty() {
      return Object.keys(this.fields).some(key => this.fields[key].dirty);
    }
  },
  beforeMount() {},
  data() {
    return {
      searchData: {
        type: ""
      },
      jobs: []
    };
  },
  methods: {
    async search(evt) {
      evt.preventDefault();
      if (!this.isFormDirty || this.errors.items.length > 0) {
        return;
      }
      const { type } = this.searchData;
      const response = await this.getJobs(this.searchData.type);
      this.jobs = response.data.jobs;
    },

    goTo(url) {
      window.open(url, "_blank");
    }
  }
};
</script>

<style lang="scss">
.md-card-header {
  .md-title {
    color: black !important;
  }
}

.md-card {
  width: 95vw;
  margin: 0 auto;
}
</style>

In the code above, we have a search form to let users search for jobs with the keyword they entered. The results are displayed in the card.

In App.vue, we replace the existing code with the following:

<template>
  <div id="app">
    <md-toolbar>
      <md-button class="md-icon-button" [@click](http://twitter.com/click "Twitter profile for @click")="showNavigation = true">
        <md-icon>menu</md-icon>
      </md-button>
      <h3 class="md-title">GraphQL Jobs App</h3>
    </md-toolbar>
    <md-drawer :md-active.sync="showNavigation" md-swipeable>
      <md-toolbar class="md-transparent" md-elevation="0">
        <span class="md-title">GraphQL Jobs App</span>
      </md-toolbar>

<md-list>
        <md-list-item>
          <router-link to="/">
            <span class="md-list-item-text">Home</span>
          </router-link>
        </md-list-item>

<md-list-item>
          <router-link to="/companies">
            <span class="md-list-item-text">Companies</span>
          </router-link>
        </md-list-item>
      </md-list>
    </md-drawer>

<router-view />
  </div>
</template>

<script>
export default {
  name: "app",
  data: () => {
    return {
      showNavigation: false
    };
  }
};
</script>

<style lang="scss">
.center {
  text-align: center;
}

form {
  width: 95vw;
  margin: 0 auto;
}

.md-toolbar.md-theme-default {
  background: #009688 !important;
  height: 60px;
}

.md-title,
.md-toolbar.md-theme-default .md-icon {
  color: #fff !important;
}
</style>

This adds a top bar and left menu to our app and allows us to toggle the menu. It also allows us to display the pages we created in the router-view element.

In main.js, we put:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import VueMaterial from 'vue-material';
import VeeValidate from 'vee-validate';
import 'vue-material/dist/vue-material.min.css'
import 'vue-material/dist/theme/default.css'
import VueApollo from 'vue-apollo';
import ApolloClient from 'apollo-boost';

Vue.config.productionTip = false
Vue.use(VeeValidate);
Vue.use(VueMaterial);
Vue.use(VueApollo);

const client = new ApolloClient({
  uri: '[https://api.graphql.jobs'](https://api.graphql.jobs%27),
  request: operation => {
    operation.setContext({
      headers: {
        authorization: ''
      },
    });
  }
});

const apolloProvider = new VueApollo({
  defaultClient: client,
})

new Vue({
  router,
  store,
  apolloProvider,
  render: h => h(App)
}).$mount('#app')

This adds the libraries we use in the app (such as Vue Material) and adds the Apollo Client to our app so we can use them in our app.

The this.$apollo object is available in our components and mixins because we inserted apolloProvider in the object we use in the argument of new Vue.

In router.js, we put:

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Companies from './views/Companies.vue'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/companies',
      name: 'companies',
      component: Companies
    }
  ]
})

Now we can see the pages we created when we navigate to them.

Categories
GraphQL JavaScript

An Introduction to GraphQL

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at how to make basic queries to a GraphQL API.

Defining the API

We define an API by defining the types and fields for those types and provide functions for each field on each type.

For example, if we have the following type:

type Query {  
  person: Person  
}

Then we have to create a function for the corresponding type to return the data:

function Query_person(request) {  
  return request.person;  
}

Making Queries

Once we have a GraphQL service running, we can send GraphQL queries to validate and execute on the server.

For example, we can make a query as follows:

{  
  person {  
    firstName  
  }  
}

Then we may get JSON like the following:

{  
  "person": {  
    "firstName": "Joe"  
  }  
}

Queries and Mutations

Queries are for getting data from the GraphQL server and mutations are used for manipulating data stored on the server.

For example, the following is a query to get a person’s name:

{  
  person {  
    name  
  }  
}

Then we may get the following JSON from the server:

{  
  "data": {  
    "person": {  
      "name": "Joe"  
    }  
  }  
}

The field name returns a String type.

We can change the query as we wish if we want to get more data. For example, if we write the following query:

{  
  person {  
    name  
    friends {  
      name  
    }  
  }  
}

Then we may get something like the following as a response:

{  
  "data": {  
    "person": {  
      "name": "Joe",  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    }  
  }  
}

The example above has friends being an array. They look the same from the query perspectively, but the server knows what to return based on the type specified.

Arguments

We can pass in arguments to queries and mutations. We can do a lot more with queries if we pass in arguments to it.

For example, we can pass in an argument as follows:

{  
  person(id: "1000") {  
    name      
  }  
}

Then we get something like:

{  
  "data": {  
    "person": {  
      "name": "Luke"  
    }  
  }  
}

from the server.

With GraphQL, we can pass in arguments to nested objects. For example, we can write:

{  
  person(id: "1000") {  
    name  
    height(unit: METER)  
  }  
}

Then we may get the following response:

{  
  "data": {  
    "person": {  
      "name": "Luke",  
      "height": 1.9  
    }  
  }  
}

In the example, the height field has a unit which is an enum type that represents a finite set of values.

unit may either be METER or FOOT.

Fragments

We can define fragments to let us reuse complex queries.

For example, we can define a fragment and use it as follows:

{  
  leftComparison: person(episode: FOO) {  
    ...comparisonFields  
  }  
  rightComparison: person(episode: BAR) {  
    ...comparisonFields  
  }  
}  
​  
fragment comparisonFields on Character {  
  name  
  appearsIn  
  friends {  
    name  
  }  
}

In the code above, we defined the comparisonFields fragment which has the list of fields we want to include in each query.

Then we have the leftComparison and rightComparison queries which include the fields of the comparisonFields fragment by using the ... operator.

Then we get something like:

{  
  "data": {  
    "leftComparison": {  
      "name": "Luke",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    },  
    "rightComparison": {  
      "name": "Mary",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Mary"  
        },  
        {  
          "name": "Alex"  
        }  
      ]  
    }  
  }  
}

Using variables inside fragments

We can pass in variables into fragments as follows:

query PersonComparison($first: Int = 3){  
  leftComparison: person(episode: FOO) {  
    ...comparisonFields  
  }  
  rightComparison: person(episode: BAR) {  
    ...comparisonFields  
  }  
}  
​  
fragment comparisonFields on Character {  
  name  
  appearsIn  
  friends(first: $first) {  
    name  
  }  
}

Then we may get something like:

{  
  "data": {  
    "leftComparison": {  
      "name": "Luke",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    },  
    "rightComparison": {  
      "name": "Mary",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Mary"  
        },  
        {  
          "name": "Alex"  
        }  
      ]  
    }  
  }  
}

as a response.

The operation type may either be a query, mutation, or subscription and describes what operator we’re intending to do. It’s required unless we’re using the query shorthand syntax. In that case, we can’t supply a name or variable definition for our operation.

The operation name is a meaningful and explicit name for our operation. It’s required in multi-operation documents. But its use is encouraged because it’s helpful for debugging and server-side logging.

It’s easy to identify the operation with a name.

Conclusion

GraphQL is a query language that lets us send requests to a server in a clear way. It works by sending nested objects with operation type and name along with any variables to the server.

Then the server will return us the response that we’re looking for.

Operation types include queries for getting data and mutations for making changes to data on the server.