Interacting with GraphQL

Interacting with GraphQL

This tutorial provides a short introduction to GraphQL terminology and explains how to interact with GraphQL-based APIs.

About GraphQL

The GraphQL data query language is:

  • A specification: The spec determines the validity of the schema on the API server, and the schema determines the validity of client calls.
  • Strongly typed: The schema defines an API's type system and all object relationships.
  • Introspective: A client can query the schema for details about the schema.
  • Hierarchical: The shape of a GraphQL call mirrors the shape of the JSON data it returns. Nested fields let you query for and receive only the data you specify in a single round trip.
  • An application layer: GraphQL is not a storage model or a database query language. The graph refers to graph structures defined in the schema. The API traverses and returns application data based on the schema definitions, independent of how the data is stored.

The GraphQL Schema Reference

The documentation in the API reference section are generated from the GraphQL schema. All calls are validated and executed against the schema. The following information determines the data that you can call:

  • Allowed operations: queries
  • Schema-defined types: scalars, objects, enums, and input objects

Note that you may need to rely on both the documentation and schema validation to successfully call the GraphQL API.

GraphQL Terminology

Schema
A schema defines a GraphQL API's type system. It describes the complete set of possible data (objects, fields, relationships, everything) that a client can access. Calls from the client are validated and executed against the schema. A client can find information about the schema via introspection, and the schema resides on the GraphQL API server.
Field

A field is a unit of data you can retrieve from an object. The official GraphQL documentation says:
"The GraphQL query language is basically about selecting fields on objects."

The official specification also says about fields:
"All GraphQL operations must specify their selections down to fields which return scalar values to ensure an unambiguously shaped response."

This means that if you try to return a field that is not a scalar, the schema validation will throw an error. You must add nested subfields until all fields return scalars.

Argument
An argument is a set of key-value pairs attached to a specific field. Some fields require an argument. Mutations require an input object as an argument.

Discovering the GraphQL API

GraphQL is introspective. This means that you can query a GraphQL schema for details about itself.

  • Query __schema to list all types defined in the schema and get details about each
  query { __schema { types { name kind description fields { name } } } }
  • Query __type to get details about any type
query { __type(name: "Conversation") { name kind description fields { name } } }

Since results are in JSON, we recommend pretty-printing them for easier reading and searching.

Note: The introspection query is probably the only GET request you'll run in GraphQL. If you're passing a body, the GraphQL request method is POST, whether it's a query or a mutation.

Communicating with GraphQL

GraphQL's operations consist of multi-line JSON. You can use cURL or any other HTTP-speaking library.

In REST, HTTP verbs determine the operation performed. In GraphQL, you'll provide a JSON-encoded body whether you're performing a query or a mutation, so the HTTP verb is POST. The exception is an introspection query, which is a simple GET to the endpoint.

To query GraphQL, we can make a POST request with a JSON payload. The payload must contain a string called query:

http
POST {{BASE_URL}}/partners/{{Partner-ID}}/data/{conversationdata}/getConversationById
Content-Type: application/json
Authorization: Basic {{Client-ID}}:{{Secret}}
x-cp-partner-id: {{Partner-ID}}
x-resource-template-version: {{template-version}}

{ “query”: “query{getConversationById(conversationId:\“39824e66-7eb1-4099-8110-ed41d7793f4d\“){conversationId}}” } 

Note: The string value of "query" must escape newline characters, or the schema will not parse it correctly. For the POST body, use outer double quotes and escaped inner double quotes.

Query and Mutation Operations

The two types of allowed operations in GraphQL are queries and mutations. Comparing GraphQL to REST, queries operate like GET requests, while mutations operate like POST/PATCH/DELETE.

Queries and mutations share similar forms, with some important differences.

About Queries

GraphQL queries return only the data you specify. To form a query, you must specify fields within fields (also known as nested subfields), until you return only scalars.

Queries are structured like this:

query {
  JSON objects to return
}

For a real-world example, see An Example Query below.

About Mutations

To form a mutation, you must specify three things:

  • Mutation name: The type of modification you want to perform.
  • Input object: The data you want to send to the server, composed of input fields. Pass it as an argument to the mutation name.
  • Payload object: The data you want to return from the server, composed of return fields. Pass it as the body of the mutation name.

Mutations are structured like this:

mutation {
  mutationName(input: {MutationNameInput!}) {
    MutationNamePayload
}

The input object in this example is MutationNameInput, and the payload object is MutationNamePayload.

Working with Variables

Variables can make queries more dynamic and powerful, and they can reduce complexity when passing mutation input objects.

Here's an example query with a single variable:

query($conversationId:String!) { getConversationById(conversationId: $conversationId) { conversationId } } variables { "conversationId": "123" }

There are three steps to using variables:

  • Define the variable outside the operation in a variables object. The object must be valid JSON. This example shows a simple String variable type, but it's possible to define more complex variable types, such as input objects. You can also define multiple variables here.

    variables { "conversationId": "123" }
  • Pass the variable to the operation as an argument. The argument is a key-value pair, where the key is the name starting with $ (e.g., $conversationId), and the value is the type (e.g., String). Add a ! to indicate whether the type is required. If you've defined multiple variables, include them here as multiple arguments.

    query($conversationId:String!) {
  • Use the variable within the operation. In this example, we substitute the variable for the conversationId to retrieve. We specify a type in step 2 because GraphQL enforces strong typing.

    getConversationById(conversationId: $conversationId) {

This process makes the query argument dynamic. We can now simply change the value in the variables object and keep the rest of the query the same.

Using variables as arguments lets you dynamically update values in the variables object without changing the query.

An Example Query

Let's walk through a query and put this information in context.

The following query looks up and returns each conversation's conversationId, originatingChannelType and all participants' ids:

query { getConversationById(conversationId:"123") { conversationId originatingChannelType participants { participantId } } }

Let's look at the composition line by line:

query {
  • Because we want to read data from the server, not modify it, query is the root operation. (If you don't specify an operation, query is also the default.)
getConversationById(conversationId:"123") {
  • To begin the query, we want to find a Conversation object. The schema validation indicates this object requires a conversationId as an argument. Now that we know we're retrieving a Conversation object, we can specify the fields we want to return:
conversationId originatingChannelType participants { participantId }
  • (Here we specify the conversationId, originatingChannelType, and participants fields of the Conversation object.)

Note: You may notice that running this query with conversationId 123 won't return anything. Try running it on with one of the valid conversationIds and you'll likely see a difference.

References

There is a lot more you can do when forming GraphQL calls. Here are some places to look next: