Basic Guide to GraphQL | weKnow Inc. Skip to main content

Basic Guide to GraphQL

With the arrival of REST API the developers world became prettier, REST allowed us to have a central space to hold all our data in one place while using multiple environments (website, android app, ios app or connect third-party systems.) But developers reached the point where we noticed something wrong on the numerous endpoint and multiple HTTP requests to obtain a minor cross data becoming a nightmare, at that point GraphQL was born! A Facebook technology with the goal to solve all issues.

Main Characteristics

GraphQL gave us just one endpoint for all our requests, making possible to combine different entity requests in one call to the API. We can define a schema of our data with strong type definition; improving error handling and the ability to see the big picture of our data. It is interrelated, working as a middle layer that can be connected to almost any backend because of a library implementation for popular programming languages (javascript, python, ruby, etc.).

Sounds like a great alternative for old REST API! Let me show you the basics of GraphQL:

Schema

GQL has its own language, we call it SCHEMA and type definition describes which data can be queried in our API.

Scalar Types

The most basic types, quite similar to “var types” of other programming languages and represent concrete values.

  • 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: The ID scalar type represents a unique identifier, often used to fetch an object again or as the key for cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies it is not intended to be human‐readable.

Enumeration Types

Also called enums, a special type of scalar that allows us to define a list of values this field can contain. Keep them in mind, they are helpful for some cases like gender or similar data.

Example:

<code>
enum Gender {
  MALE
  FEMALE
}
</code>

Object Types and Fields

We use them to map our data, similar to javascript objects and represent JSON notation, type of objects that we can receive in a query.

Example:

<code>
type Teacher {
  name: String!
  lastName: String!
}
</code>

Type modifiers

A special modifier to define not null (required) fields and list, a list is similar to define relations. An example: a teacher that has several courses.

Example:

<code>
type Course {
  name: String!
  hour: String
}
type Teacher {
  name: String!
  lastName: String
  Courses: [Course]
}
</code>

In the previews example we implemented a “course” type, then a “teacher” type. The "teacher" having multiple courses so we declare “courses” as a list of “course”, also the ! the symbol means a field is required and always should have a value.

Interfaces

Similar to OOP, GQL has abstract type interfaces including a certain set of fields that a type should include when implementing the interface, which is why is helpful to define “type” of structures for multiple types.

Example:

<code>
enum Gender {
  MALE
  FEMALE
}
enum Diet {
  CARNIVOROUS
  HERBIVOROUS
}
interface Animal {
  id: ID!
  name: String!
  gender: Gender
  diet: Diet
}
type Lion implements Animal {
  id: ID!
  name: String!
  gender: Gender
  diet: Diet
  strength: Float
}
type Elephant implements Animal {
  id: ID!
  name: String!
  gender: Gender
  diet: Diet
  Height: Float
}
</code>

In the example, we are using interfaces to implement different types of animals.

Arguments

Provide the ability to define arguments on fields, consequently they query specific data from the API. Take into account that the argument can be required or have a default value.

<code>
type Course(id: ID = 1) {
  id: ID!
  name: String
}
</code>

In the example, we are defining ID as an argument of type ID, with a default value of 1.

Query

This type is the same as a regular object type but they are special since they define the entry point of every GraphQL query.

<code>

type Course {
  name: String!
  hour: String
}
type Teacher {
  name: String!
  lastName: String
  Courses: [Course]
}
type Query {
  teachers: [Teacher]
  teacher(name: String!): Teacher
}
</code>

In the example we are defining the query for “teachers” and “teacher”; “teachers” return a list of all the teachers in the API, the second receive an argument to match the name of the teacher and it is required in case matching with some teacher name, returning the specific “teacher”.

Input Types

A special kind of object, defined to pass complex objects as arguments on our queries. Use the special word input instead of type to define objects.

<code>
input CourseInput {
  name: String!
  hour: String
}
</code>

Mutations

Not all code in the APIs is consuming data when we want to add data to our backend mutations, they are similar to the Query types but take into consideration we will receive arguments as input data.

<code>
input MessageInput {
  content: String
  author: String
}

type Message {
  id: ID!
  content: String
  author: String
}

type Query {
  getMessage(id: ID!): Message
}

type Mutation {
  createMessage(input: MessageInput): Message
  updateMessage(id: ID!, input: MessageInput): Message
}
</code>

In the example, we are defining a message type, a message input, a query that returns the message and 2 mutations. One to create a message and the other to update the message receiving different sets of arguments, this is an example of how to define a basic schema. We can use a mix of all we covered so far to create the schema as complex needed.

Querying

We already explored how to map our data, now we need to know how to query data to the API:

The query language is simple, looks like just mapping an object filled with the fields that we need returning.

Following the type “Teacher” example defined above, the query looks like this:

<code>
{
  teachers {
    name
    courses {
      name
    }
  }
}
</code>

This query will return:

<code>
{
  "data": {
    "teachers": [
      {
        "name": "john",
        "courses": [
          {
            "name": "math"
          },
          {
            "name": "spanish"
          }
        ]
      }
    ]
  }
}

</code>

We can see that the query just returns data we ask for, no lastName for “teacher” or “hour on course”, allowing us to receive the specific data we want, instead of all the data in the case with REST API’s.

With arguments

On the schema definition we covered the arguments, now let me show you how to pass arguments in a query:

<code>
{
  teacher(name: "john") {
    name
    lastName
  }
}

</code>

Return:

<code>
{
  "data": {
    "teacher": {
      "name": "john",
      "lastName": "smith"
    }
  }
}

</code>

Notice we are just passing the argument inside parenthesis then declaring what fields we want in the returned data.

Aliases

The returned data is an object that uses the name of the query as a key of the data returned, which is what happens if we need to return the teacher “john” and “george” in the same query.

<code>
{
  teacher(name: "john") {
    name
    lastName
  }
  teacher(name: "george") {
    name
    lastName
    courses {
      name
    }
  }
}
</code>

This returns an error because the key "teacher" is overlapping the resulting object, for this cases we have aliases.

<code>
{
  firstTeacher: teacher(name: "john") {
    name
    lastName
  }
  lastTeacher: teacher(name: "george") {
    name
    lastName
    courses {
      name
    }
  }
}
</code>

We are only presiding our field name with a custom one followed by the real query, returning  these:

<code>
{
  "data": {
    "firstTeacher": {
      "name": "john",
      "lastName": "smith"
    },
    "lastTeacher": {
      "name": "john",
      "lastName": "smith",
      "courses": [
        {
          "name": "math"
        },
        {
          "name": "spanish"
        }
      ]
    }
  }
}

</code>

The key to the field will be the custom one that we defined in the query.

Fragments

Fragments are another useful resource to have in mind when reusing a part of our queries. A fragment is a declaration of fields we can reuse, it's very simple! We just need to use the reserved word fragment to declare a set of fields then use 3 dot notation to call inside a query.

Example:

<code>
fragment teacherCommons on Teacher {
  name
  lastName
}

{
  firstTeacher: teacher(name: "john") {
    ...teacherCommons
  }
  lastTeacher: teacher(name: "george") {
    ...teacherCommons
    courses {
      name
    }
  }
}

</code>

This is the same example above but using fragments to call common fields from the entity ‘Teacher’ then use the fragment inside the query. Very powerful when we have several queries with the similar field, helps us reduce lines of code that are repeated in a code base.

Conclusion

These concepts cover the majority of the basics of GraphQL and it is intended as an initial approach to a more simplified world; a great alternative to REST. Implement it so you can efficiently fetch data, decouple product code and server logic. Play with it!

weKnow writes modules & themes among our ways of giving back to the community.

Learn about how we help you code more efficiently.

Check out our blog   

Summary:

GraphQL Tools that you need to check:

 

Big or Complex Project,
Not Enough Devs?

We help development teams meet their deadlines by seamlessly integrating our highly skilled developers.