# Next steps

Understanding the schema document is key to easily integrate your products with ClassDo. The schema describes the API functionalities and type specifications, and you can read about it here (opens new window).

At its core, there are 2 basic root operations in the API: Query (opens new window) & Mutation (opens new window).

Queries operations are used for fetching data and this is similar to GET requests for the REST API, while mutations operations are used to mutate data, which is like POST/PATCH/DELETE for the REST API.

# Query

Query operations are used if you want to read the data as-is without modifications. The supported query operations are encapsulated under the Viewer (opens new window) object. The Viewer object implements the Organization (opens new window) interface, which also means that the query operations are within the scope of an organisation only.

For example, name: String! simply returns the scalar value for the name of the organisation.

On the other hand, rooms(input: RoomsInput): Rooms! returns the rooms available in the organisation. As seen, this operation takes in an optional input argument of the type RoomsInput (opens new window), and returns the Rooms (opens new window) object.

# Mutation

There are also several mutation operations listed in the schema here (opens new window). Mutation operations are used if you intend to modify the data..

Let's take a look at one of them: addRoomMembers(data: RoomMembersAddInput!): [RoomMember!]!. In this case, this operation means to add room members to the room. The operation takes in a required (as indicated by the exclamation mark) input data parameter that follows the RoomMembersAddInput (opens new window) type, and returns an array of RoomMember (opens new window) object.

# Writing it in code

GraphQL is supported on a variety of languages, and can be used on almost every language that can support sending http requests. However, if you would like to use an external library as a wrapper over making raw request calls, you can consider using ClassDo's own API library (opens new window) for NodeJS applications, or any third-party libraries (opens new window) that provides a wrapper for GraphQL operations for the language of your choice. You can also use Postman (opens new window) to make API requests.

In this example, we will showcase how to send out room invitations using NodeJS step-by-step.

# Step 1: Setup NodeJS Project

To start off, we will use npm init (opens new window) to create a new project. In the project folder, create a new file called index.js.

Then, import the node-fetch (opens new window) library to help us with making requests. However, you can also use other similar libraries such as axios.

import fetch from 'node-fetch'

# Step 2: Define Mutation Operation

Now, we will start to define the query object. We use the sendInvitation (opens new window) mutation operation.

The mutation operation is defined as follows:

const query = `
  mutation sendRoomInvitation {
    sendInvitation(data: {
      # locale and contactInfo do not need to be enclosed in string,
      # because it is an Enum type
      locale: En,
      contactInfo: Email,
      contactType: 'email@example.com',
      contactFullName: 'Jack T.',
      organizationMemberRoleId: 'ROLE_ID',
      roomId: 'ROOM_ID'
    }) {
      id
      contactType
      contactInfo
      contactFullName
    }
  }
`

Breaking this down, let's understand the mutation part-by-part:

  mutation sendRoomInvitation {

Here, we want to use mutation as a root operation, so the query starts with mutation. To make it easy for understanding and readibility, we name this operation as sendRoomInvitation. You can name it any other ways that you prefer.

sendInvitation(data: {
  # locale and contactInfo do not need to be enclosed in string,
  # because it is an Enum type
  locale: En,
  contactInfo: Email,
  contactType: 'email@example.com',
  contactFullName: 'Jack T.',
  organizationMemberRoleId: 'ROLE_ID',
  roomId: 'ROOM_ID'
}) {

The following lines refer to the actual data that will be passed into the GraphQL query. We will look at how to pass in dynamic variables later. For now, the schematics of the variables in the input argument follow the schema here (opens new window).

  • The input arguments are:
    • locale*: The language that the invitation email is sent out in (either "En" or "Ja")
    • contactInfo*: The email of the invitee
    • contactType*: The method that the invitation is sent out in. It should be "Email".
    • contactFullName*: Full name of the invitee
    • organizationMemberRoleId*: The role ID of the invitee
    • roomId*: The ID of the room
    • withoutNotification: Whether the invitee would receive an email invitation

* indicates a required field.

How to obtain "INVITEE_ORGANIZATION_MEMBER_ROLE_ID"

The role ID is the unique identifier for the role that the invitee will take on in the organisation.

To obtain the role ID, there are 2 ways:

  1. Use the roles (opens new window) query operation available on ClassDo's GraphQL API.
  2. Navigate to the roles page on classdo.com and obtain the role ID from the URL path like https://app.classdo.com/orgs/<ORGANISATION_ID/roles/<ROLE_ID>
How to obtain "ROOM_ID"

The room ID is the unique identifier for the room that you are inviting the invitee to.

There are 2 quick ways to obtain the room ID:

  1. Use the rooms (opens new window) query operation available on ClassDo's GraphQL API.
  2. Navigate to the organisation homepage on classdo.com and obtain the room ID from the url path like https://app.classdo.com/orgs/<ORGANISATION_ID>/rooms/<ROOM_ID>

# Step 3: Specify the data to return

  id
  contactType
  contactInfo
  contactFullName
}
  }

Now, we can choose precisely what data we want to obtain from the query. This is one of the many strengths of GraphQL. We can see the schema for the Invitation object being returned here (opens new window).

To keep our example simple, we will only return the id, contactType, contactInfo, and contactFullName. These are also known as scalar values, as they do not need to be unwrapped further.

# Step 4: Making a GraphQL request

With our queries well-defined, it is time to start making the GraphQL request.

Making your first API call

If you are not yet familiar with making API calls for GraphQL, please check out this article.

fetch('https://api.classdo.com/graphql', {
  method: 'POST',
  body: JSON.stringify({
    query
  }),
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'TOKEN'
  }
})

To make our request, we need to be clear of 4 parts:

  • endpoint: The request endpoint is https://api.classdo.com/graphql, which points to ClassDo's public API server.
  • method: We use the POST method to be able to send the payload.
  • body: The payload body takes in a JSON-encoded object for the query.
  • headers: For the headers, we need to specify 2 parts, the Content-Type, which is application/json, and the x-api-key, which is assigned the generated API token.
.then((res) => {
  return res.json()
})
.then((res) => {
  if (res.errors) {
    throw res.errors
  }
  const { id, contactType, contactInfo, contactFullName } = res.data.sendInvitation
})

Now, we can retrieve the response that was returned by the earlier async request call. First, we parse the response to a JSON format and handle any possible errors.

Then, the fields that were specified earlier can simply be obtained by unwrapping res.data.sendInvitation.

You can see immediately that the query has exactly the same shape as the result. This is essential to GraphQL, because you always get back what you expect, and the server knows exactly what fields the client is asking for.

# Bonus: Working with variables

Up till now, we have been writing the arguments directly inside the query. But, in many cases, we require the arguments to be dynamic. In GraphQL, the variables are abstracted out of the query string, and can be handled in a separate object like so:

const variables = {
  locale: 'En',
  contactInfo: 'email@example.com',
  contactType: 'Email',
  contactFullName: 'Jack T.',
  organizationMemberRoleId: 'ROLE_ID',
  roomId: 'ROOM_ID'
}

You can read more about it here (opens new window).

Now, we can start to make a few minor adjustments to the query string that was defined earlier. This is done in 2 simple steps:

  1. Pass the argument fields to the sendRoomInvitation operation.
  • Each argument that is passed into the operation follows the format like $ArgumentName: ArgumentType or $ArgumentName: ArgumentType!.
mutation sendRoomInvitation(
  # Define the argument name and argument data type
  $locale: Locale!,
  $contactInfo: String!,
  $contactType: ContactType!,
  $contactFullName: String!,
  $organizationMemberRoleId: String!,
  $roomId: ID!
) {
  1. Use the arguments as variables for the query.
# Pass the arguments as variables
sendInvitation(data: {
  locale: $locale,
  contactInfo: $contactInfo,
  contactType: $contactType,
  contactFullName: $contactFullName,
  organizationMemberRoleId: $organizationMemberRoleId,
  roomId: $roomId
}) {

The complete mutation variable looks like:

Mutation operation
const query = `
  mutation sendRoomInvitation(
    # Define the argument name and argument data type
    $locale: Locale!,
    $contactInfo: String!,
    $contactType: ContactType!,
    $contactFullName: String!,
    $organizationMemberRoleId: String!,
    $roomId: ID!
  ) {
    # Pass the arguments as variables
    sendInvitation(data: {
      locale: $locale,
      contactInfo: $contactInfo,
      contactType: $contactType,
      contactFullName: $contactFullName,
      organizationMemberRoleId: $organizationMemberRoleId,
      roomId: $roomId
    }) {
      id
      contactType
      contactInfo
      contactFullName
    }
  }
`

To make the API call, we only need to pass in the variables object to the request payload like so:

fetch('https://api.classdo.com/graphql', {
  method: 'POST',
  body: JSON.stringify({
    query,
    variables
  }),
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'TOKEN'
  }
})

# Step 5: Summary

Now, that you are familiar with how to work with GraphQL in context, please checkout the cookbook for some common API recipes to help you integrate with ClassDo.

You can find the complete set of walkthrough code for below:

Complete code
import fetch from 'node-fetch'

const query = `
  mutation sendRoomInvitation(
    # Define the argument name and argument data type
    $locale: Locale!,
    $contactInfo: String!,
    $contactType: ContactType!,
    $contactFullName: String!,
    $organizationMemberRoleId: String!,
    $roomId: ID!
  ) {
    # Pass the arguments as variables
    sendInvitation(data: {
      locale: $locale,
      contactInfo: $contactInfo,
      contactType: $contactType,
      contactFullName: $contactFullName,
      organizationMemberRoleId: $organizationMemberRoleId,
      roomId: $roomId
    }) {
      id
      contactType
      contactInfo
      contactFullName
    }
  }
`

const variables = {
  locale: 'En',
  contactInfo: 'email@example.com',
  contactType: 'Email',
  contactFullName: 'Jack T.',
  organizationMemberRoleId: 'ROLE_ID',
  roomId: 'ROOM_ID'
}

fetch('https://api.classdo.com/graphql', {
  method: 'POST',
  body: JSON.stringify({
    query,
    variables
  }),
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'TOKEN'
  }
})
  .then((res) => {
    return res.json()
  })
  .then((res) => {
    if (res.errors) {
      throw res.errors
    }
    const { id, contactType, contactInfo, contactFullName } = res.data.sendInvitation
  })