Skip to main content
Version: 3.0 (next)

GraphQL GraphQL Integration Guide

Read from and write to MES, ERP and SaaS systems that offer a GraphQL API, with variables from the pipeline and the server's own error messages when something fails.

Authentication
None · Basic · Bearer · API key header · OAuth2 token
Operations
Query · Mutation
Transport
GraphQL over HTTP (POST, JSON)

Overview​

The GraphQL connector sends queries and mutations to one GraphQL endpoint, such as https://mes.plant.local/graphql, as GraphQL over HTTP: a POST with a JSON body holding the document, its variables and an optional operation name.

  • Query: read data, such as a work order's status or a material's stock.
  • Mutation: change data, such as reporting a produced quantity or closing a work order.

Why not the REST connector? A GraphQL server usually answers 200 OK even when the operation failed: the failure is in the errors list of the answer. A REST call would report that as a success. This connector reads errors and fails the node with the server's own message, and decides whether trying again can help.

Pipeline values go in variables, never in the document. The document is sent exactly as you wrote it, so a value from upstream can never change which operation runs.

Prerequisites​

  • The endpoint URL of the GraphQL API, and credentials if it needs them.
  • A server that answers ordinary queries. The connection check sends query MaestroHubConnectionCheck { __typename }, which every GraphQL server answers, also with introspection turned off. A server that only runs a fixed list of allowed (persisted) operations refuses it; add that query to its allow list.

Connection Configuration​

Navigate to Connections → New Connection → GraphQL.

GraphQL connection formGraphQL connection form

The Connection tab: the endpoint URL and custom headers

Connection​

FieldDefaultDescription
Profile Name-A descriptive name for this connection (required, at most 100 characters)
Description-Optional
Endpoint URL-The URL every query and mutation is posted to, e.g. https://api.example.com/graphql (required). http and https are both accepted; use https whenever the connection carries credentials
Custom Headers-Headers sent with every request, e.g. a client name or a tenant header the API asks for

Authentication​

Authentication TypeFieldsWhat is sent
None-No credentials
BasicUsername, PasswordAuthorization: Basic …
BearerBearer TokenAuthorization: Bearer <token>
API KeyAPI Key Header (default X-API-Key), API KeyThe key in that header, e.g. x-hasura-admin-secret
Web Token (OAuth2)Token URL, Token Request Body, Token Request Encoding (default form), Token Request Headers, Token Response Path (default access_token), Token Header Name (default Authorization), Prepend Bearer (default on), Token Cache Duration (default 5m)A token fetched from the token endpoint, e.g. with {"grant_type": "client_credentials", "client_id": "…", "client_secret": "…"} as the body

These are the same authentication types the REST and SOAP connectors offer. Passwords, tokens, keys and the token request body are stored encrypted and masked when you edit the connection. A token refused by the token endpoint (invalid_client, a 401) is reported as a refusal, not an outage.

TLS​

FieldDefaultDescription
CA Certificate (PEM)-The CA that signed the server's certificate, for a private or self-signed server. Leave empty to trust the system's CAs
Client Certificate / Client Private Key (PEM)-For mutual TLS. Both or neither
Skip Certificate VerificationOffAccepts any server certificate. Use it only to test against a server with a self-signed certificate
Notes
  • Redirects are not followed: a redirected POST would arrive as a GET. Set the endpoint URL to the final address.
  • Concurrency: at most ten requests run at once per connection. One GraphQL query can fan out to many back-end calls on the server.

Function Builder​

After saving the connection, open its Functions tab → New Function and choose Query or Mutation.

GraphQL function typesGraphQL function types

Query reads, Mutation writes

Both functions take the same fields:

FieldRequiredDescription
Query / MutationYesThe GraphQL document, e.g. query WorkOrder($id: ID!) { workOrder(id: $id) { id status quantity } }. Sent as written: it cannot hold ((parameters))
VariablesNoA JSON object of the document's variables, e.g. {"id": "((workOrderId))"}. Supports ((parameters))
Operation NameNoWhich operation to run when the document holds several
TimeoutNoBound on this operation, 30s by default

Each function checks the document before anything is sent:

  • The Query function runs only queries. A document whose operation is a mutation or a subscription is refused, so a write cannot run through a read function and past the rules that guard writes. The Mutation function runs only mutations.
  • A document with several operations needs an Operation Name that names one of them.
  • A ((parameter)) inside the document is refused when you save: put it in Variables and refer to it as $name.
  • Variables must be a JSON object once their parameters are filled.

The server still validates the document against its schema; its answer is shown when it refuses.

GraphQL function parametersGraphQL function parameters

A Query function whose variables carry the ((workOrderId)) parameter

A mutation is not repeated safely

GraphQL defines no idempotency key: a mutation sent twice may act twice (two records created, a quantity reported twice). The connector never retries by itself. A mutation whose answer was lost (a timeout, a dropped connection) may already have run on the server: check the server before running it again. With store-and-forward on, such a mutation is sent again when the link returns, the same trade the REST connector's POST makes.

How Answers Become Results​

GraphQL can answer part of what you asked and fail the rest in one response: a field whose resolver failed is null, with an error naming its path. The connector reports each case like this:

The server answeredThe nodeRetry on Fail helps?
data, no errorsSucceeds. result.data holds the data; result.errors is empty-
data with at least one non-null root field, and errors (partial data)Succeeds, with the errors in result.errors and a warning in _metadata.warning. The server ran the operation, so a mutation may have acted: failing it would invite a second run. Branch on result.errors when a missing field matters-
errors and no data, or every root field nullFails with the server's messages. Permanent: the same request gets the same answerNo
… and an error says "try again": code THROTTLED, RATE_LIMITED, TOO_MANY_REQUESTS, SERVICE_UNAVAILABLE, TIMEOUT, INTERNAL_SERVER_ERROR and the like, or an HTTP status 408, 429 or 5xx in the error's extensionsFails, temporaryYes
HTTP 400, 401, 403, 404 (with or without GraphQL errors)Fails, permanent. A server that speaks application/graphql-response+json answers a syntax or validation error with 400No
HTTP 408, 429, 5xx, a network failure, a timeoutFails, temporary: a mutation may have runYes
A 200 that is not a GraphQL answer (an HTML login page, a REST root)Fails, temporary, saying the endpoint answered something elseYes

The error code is read from extensions.code (Apollo, Hasura, Shopify), extensions.classification (graphql-java) or the error's type (GitHub).

Pipeline Integration​

Each operation is its own node in the Pipeline Designer, under APIs: GraphQL Query and GraphQL Mutation. The GraphQL nodes page lists what they return.

GraphQL Query nodeGraphQL Query node

The GraphQL Query node with its connection and function

Common Use Cases​

Report production to the MES when a batch ends​

  1. A trigger fires when the batch counter resets.
  2. GraphQL Mutation with mutation Report($id: ID!, $qty: Int!) { reportQuantity(workOrder: $id, quantity: $qty) { id produced } } and variables {"id": "((workOrderId))", "qty": ((count))}.

Check stock before reordering​

GraphQL Query with query Stock($m: ID!) { material(id: $m) { onHand reorderPoint } }, then a condition on $node["Stock"].result.data.material.onHand.

Troubleshooting​

What you seeCause and fix
"the Query function runs only queries"The document is a mutation. Create a Mutation function for it
"set Operation Name to choose one"The document holds several operations. Name the one to run
"is not a GraphQL response"The endpoint URL points at a login page, a proxy page or the API's REST root. Use the GraphQL endpoint itself, often ending in /graphql
401 or UNAUTHENTICATEDWrong or missing credentials. Check the authentication type and the header the API expects
Cannot query field … on type … (400)The document does not match the server's schema. Check field names in the API's documentation or schema explorer
Variable $x got invalid valueA variable's value does not fit its declared type, e.g. text for an Int!. Check the upstream value and the variables JSON
THROTTLED / rate limitedThe API's rate limit. The failure is temporary; lower the pipeline's rate
Connection check fails on a working APIThe server runs only allow-listed operations. Allow query MaestroHubConnectionCheck { __typename }
Redirected (3xx)The endpoint moved, or a login page answered. Use the final URL