Skip to Content
SDK & PluginsPluginsGraphQL Plugin

GraphQL Plugin (@glubean/graphql)

@glubean/graphql is a first-party GraphQL client plugin for Glubean.

Status: Experimental (pre-1.0). API may evolve.

Install

npm install @glubean/graphql

Project setup — install the plugin manifest

@glubean/graphql ships two things: a plugin manifest (registers the graphql contract protocol, toHaveGraphql* matchers, and toHaveHttpStatus) and the client factory shown in the quick start below. The manifest must be installed once per project from glubean.setup.ts at the project root:

// glubean.setup.ts import { installPlugin } from "@glubean/sdk"; import graphqlPlugin from "@glubean/graphql"; await installPlugin(graphqlPlugin);

Without this file, contract.graphql.with(...) and ctx.expect(result).toHaveGraphqlData(...) will throw “unknown protocol” / missing-matcher errors at runtime. A top-level import "@glubean/graphql" no longer auto-registers these globals.

Quick Start (configure plugin mode)

import { configure, test } from "@glubean/sdk"; import { graphql } from "@glubean/graphql"; const { gql } = configure({ plugins: { gql: graphql({ endpoint: "{{GRAPHQL_URL}}", headers: { Authorization: "Bearer {{API_KEY}}" }, throwOnGraphQLErrors: true, }), }, }); export const getUser = test("get-user", async (ctx) => { const { data } = await gql.query<{ user: { name: string } }>( `query GetUser($id: ID!) { user(id: $id) { name } }`, { variables: { id: "1" } }, ); ctx.expect(data?.user.name).toBe("Alice"); });

Contract protocol

Use contract.graphql.with(...) when the GraphQL operation is a durable API promise that should run as a check and project into Specifications.

import { configure, contract } from "@glubean/sdk"; import { gql, graphql } from "@glubean/graphql"; const { graph } = configure({ plugins: { graph: graphql({ endpoint: "{{GRAPHQL_URL}}", headers: { Authorization: "Bearer {{API_KEY}}" }, }), }, }); const userGraph = contract.graphql.with("userGraph", { client: graph, endpoint: "{{GRAPHQL_URL}}", tags: ["users"], }); export const userLookup = userGraph("user-lookup", { description: "Users can be fetched by id", cases: { ok: { description: "existing user returns profile fields", operation: "query", query: gql` query GetUser($id: ID!) { user(id: $id) { id name } } `, variables: { id: "1" }, expect: { errors: "absent", data: { user: { id: "1" } }, }, }, }, });

The client owns the runtime endpoint. The optional endpoint value on the contract instance is projection/display metadata so Specifications can show where the promise points.

Standalone mode (createGraphQLClient)

Use this when you need a one-off GraphQL client instead of a named configure({ plugins }) client. In real projects, still keep environment access in configure().

import { configure, test } from "@glubean/sdk"; import { createGraphQLClient } from "@glubean/graphql"; const { http, vars, secrets } = configure({ vars: { gqlUrl: "{{GQL_URL}}" }, secrets: { token: "{{TOKEN}}" }, }); export const quick = test("quick-gql", async (ctx) => { const gql = createGraphQLClient(http, { endpoint: vars.gqlUrl, headers: { Authorization: `Bearer ${secrets.token}` }, }); const { data } = await gql.query<{ health: string }>(`{ health }`); ctx.expect(data?.health).toBe("ok"); });

Extra helpers

gql tagged template

Identity tag for better GraphQL editor highlighting:

import { gql } from "@glubean/graphql"; const GET_USER = gql` query GetUser($id: ID!) { user(id: $id) { id name email } } `;

fromGql(path)

Load query text from .gql files:

import { fromGql } from "@glubean/graphql"; const GET_USER = await fromGql("./queries/get-user.gql");

Client methods

  • gql.query<T>(query, options?) — execute a query
  • gql.mutate<T>(mutation, options?) — execute a mutation

Both return Promise<{ data: T | null; errors?: GraphQLError[] }>.

Options

OptionTypeDefaultDescription
endpointstring(required)GraphQL endpoint URL ({{KEY}} supported)
headersRecord<string, string>{}Default headers ({{KEY}} supported)
throwOnGraphQLErrorsbooleanfalseThrow when errors array is non-empty

Next

Last updated on