Introducing GraphQL

GraphQL is an open specification for an API query language (thus the “QL” reference) that lets you make your integrations more responsive than ever by providing you with the ability to request the data you need and nothing more. GraphQL can also reduce the number of calls and associated round trips you are making by fetching all of the resources you need in a single, or fewer calls.

In short, GraphQL will measurably impact your integrations by reducing bandwidth overhead due to response payload sizes and also the number of calls being made.

Note:

API filters continue to be a key feature that should still be used to reduce resource usage when making REST API GET calls.

OIDC/OAuth2

Coupa’s GraphQL query endpoint is authenticated using OIDC and authorization is handled using OAuth2 scopes. Go to Setup > Integrations > Oauth2/OpenID Connect Clients and click the Create button (or go to /oauth2/clients/new) to create an OIDC client with the appropriate OAuth2 read scopes for your queries (writing is not yet supported). We currently only support client credentials grant types.

After creating an OIDC client, use the OIDC client information to retrieve an access token. We won’t go into discussing how to obtain an access token. Contact your Coupa Administrator or Coupa Support for steps on how to retrieve an access token with your OIDC client information.

GraphQL clients

After you have an access token, there are many tools available that can be used to make GraphQL requests to Coupa. These tools include curl, Postman, and GraphiQL.

In the following examples, we will be using GraphQL. One of the main advantages to using GraphQL is that it fetches the schema and allows you to explore the schema in a user friendly way.

Download GraphiQL from https://www.electronjs.org/apps/graphiql or, if you're a Mac user with Homebrew installed, use the following command:

        brew install --cask graphiql
      

After installing GraphiQL, launch it and you’ll see something similar to the image below:

Things to note in the above image:

  • Provide your instance URL and append it with /api/graphql in the GraphQL Endpoint address bar.

  • Edit the HTTP headers to add your access token to the Authorization header (See image below).

  • Click on Docs to expand to show the schema.

When editing the header, add an authorization header by clicking the Add Header button and the following information:

  • Header name: Authorization
  • Header value: bearer {your access token}

Make sure to prefix the Header value with bearer or you won't be able to authorize.

Schema

Expanding the Docs in GraphiQL will allow you to explore the schema. With the schema, you can find out what is queryable and the return types for the queries.

Warning:

Mutations are not supported and should not be used.

Queries

With GraphQL, you can query specifically for the data you need. You can query for data for a single object, or a collection of objects.

Single objects

To query for a single object, use the singular form of the object name in lower camel case and specify the object ID. For example, user(id: 1), expenseReport(id: 1).

Data is returned in JSON format with the data for the fields queried.

Collections

To query for a collection of objects, use the plural form of the object name in lower camel case. For example, users, expenseReports.

Associations

GraphQL allows you to query for nested data:

The image above shows a query for a single expense report (this also works for a collection of objects). In the expense report, we are querying for who created it and additional information on the report’s expense lines. Notice that even within expense lines we are querying for nested data.

Custom Fields

Objects may have custom fields that can be queried by the field name customFields:

Custom fields can be any of a number of types (eg: text, datetime, user, etc…). The customFields field can reveal what the type is for that specific custom field, which will allow you to query for those types specifically using fragments.

Fragments

Fragments let you construct sets of fields, and then include them in queries. For customFields, you can specify fragments at the type level:

In the above example, we specify two fragments: … on User { … } and … on StringValue { … }. The fragments tell Coupa to attempt to convert the custom fields to the specified types (if applicable). If it can be converted to that given type, then the fields requested will be returned.

Advanced filtering and querying options

Collection queries have the additional option parameter called query that further filters out responses. The format for the query option is in the form of a query string parameter that’s also used to filter out values in our REST APIs.

The above example uses "id[lt_or_eq]=5" for the query parameter which filters out ID values to less than 5. This can also be dropped straight into our REST APIs in the form of /api/invoices?id[lt_or_eq]=5.

Errors

When checking responses, you should always check to see if the JSON response has any errors. If there are errors, a message and details of the error are shown:

Introspection

You can also query GraphQL for the schema itself. This is what GraphQL does to generate the schema for its clients. Here is an example of typical introspection query:

query IntrospectionQuery {
		__schema {
			queryType { name }
			mutationType { name }
			subscriptionType { name }
			types {
				...FullType
			}
			directives {
				name
				description
				args {
					...InputValue
				}query IntrospectionQuery {
	__schema {
		queryType {
			name
		}
		mutationType {
			name
		}
		subscriptionType {
			name
		}
		types {
			...FullType
		}
		directives {
			name
			description
			args {
				...InputValue
			}
			onOperation
			onFragment
			onField
		}
	}
}

fragment FullType on __Type {
	kind
	name
	description
	fields(includeDeprecated: true) {
		name
		description
		args {
			...InputValue
		}
		type {
			...TypeRef
		}
		isDeprecated
		deprecationReason
	}
	inputFields {
		...InputValue
	}
	interfaces {
		...TypeRef
	}
	enumValues(includeDeprecated: true) {
		name
		description
		isDeprecated
		deprecationReason
	}
	possibleTypes {
		...TypeRef
	}
}

fragment InputValue on __InputValue {
	name
	description
	type {
		...TypeRef
	}
	defaultValue
}

fragment TypeRef on __Type {
	kind
	name
	ofType {
		kind
		name
		ofType {
			kind
			name
			ofType {
				kind
				name
			}
		}
	}
}

				onOperation
				onFragment
				onField
			}
		}
	}

	fragment FullType on __Type {
		kind
		name
		description
		fields(includeDeprecated: true) {
			name
			description
			args {
				...InputValue
			}
			type {
				...TypeRef
			}
			isDeprecated
			deprecationReason
		}
		inputFields {
			...InputValue
		}
		interfaces {
			...TypeRef
		}
		enumValues(includeDeprecated: true) {
			name
			description
			isDeprecated
			deprecationReason
		}
		possibleTypes {
			...TypeRef
		}
	}

	fragment InputValue on __InputValue {
		name
		description
		type { ...TypeRef }
		defaultValue
	}

	fragment TypeRef on __Type {
		kind
		name
		ofType {
			kind
			name
			ofType {
				kind
				name
				ofType {
					kind
					name
				}
			}
		}
	}

GraphQL using Postman

All GraphQL examples mentioned above can also be run in Postman by following these steps:

  1. Generate an OIDC token in Coupa. See aaaaaaaaaaaaaaaaaaaaaaaa for details.

  2. Once the access token is generated, use it to initiate GraphQL request with the following POSTMAN configuration:

Important notes

  • All requests are POST requests

  • All responses are in JSON only

  • Always check the response body for errors, even if the response code of 200 was returned