gatsby-source-graphql is a Gatsby plugin that enables integration of third-party GraphQL APIs into Gatsby's unified GraphQL layer through schema stitching. It wraps remote schema Query types under configurable field names within the Gatsby GraphQL query structure, supporting authentication, custom Apollo Links, query batching, and schema transformation capabilities.
npm install gatsby-source-graphqlThis is a Gatsby plugin, so it's configured in gatsby-config.js rather than imported directly:
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: "gatsby-source-graphql",
options: {
// Configuration options
},
},
],
};// gatsby-config.js
module.exports = {
plugins: [
{
resolve: "gatsby-source-graphql",
options: {
// Arbitrary name for the remote schema Query type
typeName: "SWAPI",
// Field under which the remote schema will be accessible
fieldName: "swapi",
// GraphQL endpoint URL
url: "https://swapi-graphql.netlify.app/.netlify/functions/index",
},
},
],
};Then query the remote GraphQL API through Gatsby's GraphQL layer:
{
swapi {
allSpecies {
name
classification
}
}
}Defines and validates the plugin configuration options using Joi schema validation.
/**
* Gatsby plugin option validation schema
* @param {{ Joi: typeof import('joi') }} gatsbyAPI - Gatsby API with Joi validation library
* @returns {import('joi').ObjectSchema} Joi validation schema for plugin options
*/
function pluginOptionsSchema({ Joi });Configuration Options:
interface PluginOptions {
/** Arbitrary name for the remote schema Query type (required) */
typeName: string;
/** Field name under which the remote schema will be accessible (required) */
fieldName: string;
/** GraphQL endpoint URL (required if no createLink) */
url?: string;
/** HTTP headers or async function returning headers */
headers?: Record<string, string> | (() => Promise<Record<string, string>>);
/** Custom fetch implementation */
fetch?: (uri: string, options?: any) => Promise<Response>;
/** Additional options to pass to fetch */
fetchOptions?: Record<string, any>;
/** Custom Apollo Link factory function */
createLink?: (options: PluginOptions) => Promise<import('@apollo/client').ApolloLink>;
/** Custom schema factory function */
createSchema?: (options: PluginOptions) => Promise<import('graphql').GraphQLSchema>;
/** Enable query batching for performance */
batch?: boolean;
/** Custom schema transformation function */
transformSchema?: (params: TransformSchemaParams) => import('graphql').GraphQLSchema;
/** DataLoader configuration options */
dataLoaderOptions?: DataLoaderOptions;
/** Refetch interval in seconds (development only) */
refetchInterval?: number;
}
interface TransformSchemaParams {
schema: import('graphql').GraphQLSchema;
link: import('@apollo/client').ApolloLink;
resolver: (parent: any, args: any, context: any, info: any) => any;
defaultTransforms: Array<any>;
options: PluginOptions;
}
interface DataLoaderOptions {
batch?: boolean;
maxBatchSize?: number;
batchScheduleFn?: (callback: () => void) => void;
cache?: boolean;
cacheKeyFn?: (key: any) => any;
cacheMap?: {
get: (key: any) => any;
set: (key: any, value: any) => void;
delete: (key: any) => boolean;
clear: () => void;
};
}Integrates the remote GraphQL schema into Gatsby's unified GraphQL layer.
/**
* Gatsby hook that integrates remote GraphQL schema into Gatsby's schema
* @param {GatsbyCreateSchemaCustomizationAPI} gatsbyAPI - Gatsby API with actions, createNodeId, cache
* @param {PluginOptions} options - Plugin configuration options
* @returns {Promise<void>}
*/
async function createSchemaCustomization(gatsbyAPI, options);
interface GatsbyCreateSchemaCustomizationAPI {
actions: {
addThirdPartySchema: (params: { schema: import('graphql').GraphQLSchema }) => void;
};
createNodeId: (input: string) => string;
cache: {
get: (key: string) => Promise<any>;
set: (key: string, value: any) => Promise<void>;
};
}Creates schema tracking nodes for cache invalidation and refetching capabilities.
/**
* Gatsby hook that creates schema tracking node for cache invalidation and refetching
* @param {GatsbySourceNodesAPI} gatsbyAPI - Gatsby API with actions, createNodeId, createContentDigest
* @param {PluginOptions} options - Plugin configuration options
* @returns {Promise<void>}
*/
async function sourceNodes(gatsbyAPI, options);
interface GatsbySourceNodesAPI {
actions: {
createNode: (node: GatsbyNode) => void;
};
createNodeId: (input: string) => string;
createContentDigest: (input: any) => string;
}
interface GatsbyNode {
id: string;
typeName: string;
fieldName: string;
parent: string | null;
children: string[];
internal: {
type: string;
contentDigest: string;
ignoreType: boolean;
};
}Provides schema transformation classes for customizing how remote schemas are integrated.
/**
* Transforms remote schema to be nested under specified field name
*/
class NamespaceUnderFieldTransform {
/**
* @param {Object} params - Transform parameters
* @param {string} params.typeName - Name for the wrapped query type
* @param {string} params.fieldName - Field name for accessing remote schema
* @param {Function} params.resolver - Custom resolver function
*/
constructor({ typeName, fieldName, resolver });
/**
* Applies namespace transformation to GraphQL schema
* @param {import('graphql').GraphQLSchema} schema - Input GraphQL schema
* @returns {import('graphql').GraphQLSchema} Transformed schema
*/
transformSchema(schema);
}
/**
* Removes Mutation and Subscription types from remote schema
*/
class StripNonQueryTransform {
/**
* Strips non-Query operations from GraphQL schema
* @param {import('graphql').GraphQLSchema} schema - Input GraphQL schema
* @returns {import('graphql').GraphQLSchema} Transformed schema with only Query type
*/
transformSchema(schema);
}Enhanced fetch wrapper with GraphQL-specific error handling.
/**
* Enhanced fetch wrapper with error handling for GraphQL requests
* @param {string} uri - Request URL
* @param {RequestInit} options - Fetch options
* @returns {Promise<Response>} Response object
* @throws {Error} Descriptive errors for HTTP status >= 400
*/
async function fetchWrapper(uri, options);Apollo Link implementation with DataLoader for automatic query batching and performance optimization.
/**
* Creates Apollo Link with DataLoader for query batching
* @param {BatchingOptions} options - Configuration for batching behavior
* @returns {import('@apollo/client').ApolloLink} Apollo Link instance with batching support
*/
function createDataloaderLink(options);
interface BatchingOptions {
uri: string;
headers?: Record<string, string>;
fetch: (uri: string, options?: any) => Promise<Response>;
fetchOptions?: Record<string, any>;
dataLoaderOptions?: DataLoaderOptions;
}Utilities for merging multiple GraphQL queries into batched requests.
/**
* Merges multiple GraphQL queries into single batched query
* @param {QueryRequest[]} queries - Array of query objects
* @returns {BatchedQuery} Object with merged query and variables
*/
function merge(queries);
/**
* Splits merged query result back into individual query results
* @param {GraphQLResult} mergedQueryResult - Result from merged query
* @returns {GraphQLResult[]} Array of individual query results
*/
function resolveResult(mergedQueryResult);
interface QueryRequest {
query: import('graphql').DocumentNode;
variables: Record<string, any>;
}
interface BatchedQuery {
query: import('graphql').DocumentNode;
variables: Record<string, any>;
}
interface GraphQLResult {
data?: any;
errors?: Array<{
message: string;
path?: Array<string | number>;
}>;
}{
resolve: "gatsby-source-graphql",
options: {
typeName: "GitHub",
fieldName: "github",
url: "https://api.github.com/graphql",
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
},
},
}{
resolve: "gatsby-source-graphql",
options: {
typeName: "API",
fieldName: "api",
url: "https://api.example.com/graphql",
headers: async () => {
const token = await getAuthToken();
return {
Authorization: `Bearer ${token}`,
};
},
},
}const { createHttpLink, from } = require("@apollo/client");
const { RetryLink } = require("@apollo/client/link/retry");
{
resolve: "gatsby-source-graphql",
options: {
typeName: "API",
fieldName: "api",
createLink: (pluginOptions) => {
const retryLink = new RetryLink({
delay: { initial: 100, max: 2000, jitter: true },
attempts: { max: 5 },
});
return from([retryLink, createHttpLink({ uri: "https://api.example.com/graphql" })]);
},
},
}{
resolve: "gatsby-source-graphql",
options: {
typeName: "API",
fieldName: "api",
url: "https://api.example.com/graphql",
batch: true,
dataLoaderOptions: {
maxBatchSize: 10,
batchScheduleFn: (callback) => setTimeout(callback, 50),
},
},
}const { buildSchema, buildClientSchema } = require("graphql");
{
resolve: "gatsby-source-graphql",
options: {
typeName: "API",
fieldName: "api",
url: "https://api.example.com/graphql",
createSchema: async () => {
const introspectionResult = JSON.parse(
fs.readFileSync(`${__dirname}/schema.json`)
);
return buildClientSchema(introspectionResult.data);
},
},
}const { wrapSchema } = require("@graphql-tools/wrap");
const { linkToExecutor } = require("@graphql-tools/links");
{
resolve: "gatsby-source-graphql",
options: {
typeName: "API",
fieldName: "api",
url: "https://api.example.com/graphql",
transformSchema: ({ schema, link, resolver, defaultTransforms, options }) => {
return wrapSchema({
schema,
executor: linkToExecutor(link),
transforms: defaultTransforms,
});
},
},
}{
resolve: "gatsby-source-graphql",
options: {
typeName: "API",
fieldName: "api",
url: "https://api.example.com/graphql",
refetchInterval: 60, // Refetch every 60 seconds in development
},
}Enable batching for improved performance when making multiple GraphQL queries:
batch: true to enable automatic query mergingGATSBY_EXPERIMENTAL_QUERY_CONCURRENCY environment variabledataLoaderOptions.maxBatchSize for optimal batch sizes.cache directorycreateSchema to disable cachinggatsby develop or deleting .cache