Batch operations enable sending multiple GraphQL documents in a single HTTP request, optimizing network usage and providing atomic transaction capabilities. This is particularly useful for applications that need to execute related queries or mutations together.
Static function for sending multiple GraphQL documents in a single request.
/**
* Send multiple GraphQL documents in a batch request
* @param url - GraphQL endpoint URL
* @param documents - Array of documents with optional variables
* @param requestHeaders - Optional headers for the batch request
* @returns Promise resolving to array of results
*/
function batchRequests<T extends BatchResult, V extends Variables = Variables>(
url: string,
documents: BatchRequestDocument<V>[],
requestHeaders?: HeadersInit
): Promise<T>;
/**
* Send batch requests using an options object
* @param options - Complete batch request configuration
* @returns Promise resolving to array of results
*/
function batchRequests<T extends BatchResult, V extends Variables = Variables>(
options: BatchRequestsExtendedOptions<V>
): Promise<T>;
interface BatchRequestsExtendedOptions<V extends Variables = Variables> {
url: string;
documents: BatchRequestDocument<V>[];
requestHeaders?: HeadersInit;
signal?: RequestInit["signal"];
}
type BatchResult = [Result, ...Result[]];
interface Result<Data extends object = object> {
data: Data;
}Usage Examples:
import { batchRequests, gql } from "graphql-request";
// Define multiple queries
const getUserQuery = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
const getPostsQuery = gql`
query GetPosts($userId: ID!) {
posts(userId: $userId) {
id
title
content
}
}
`;
// Batch request with multiple queries
const [userResult, postsResult] = await batchRequests(
"https://api.example.com/graphql",
[
{
document: getUserQuery,
variables: { id: "123" },
},
{
document: getPostsQuery,
variables: { userId: "123" },
},
]
);
console.log("User:", userResult.data);
console.log("Posts:", postsResult.data);
// Using options object for batch requests
const results = await batchRequests({
url: "https://api.example.com/graphql",
documents: [
{ document: getUserQuery, variables: { id: "123" } },
{ document: getPostsQuery, variables: { userId: "123" } },
],
requestHeaders: {
authorization: "Bearer TOKEN",
},
});
// Batch mutations (atomic operations)
const createUserMutation = gql`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
}
}
`;
const createPostMutation = gql`
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
}
}
`;
const [userCreated, postCreated] = await batchRequests(
"https://api.example.com/graphql",
[
{
document: createUserMutation,
variables: {
input: { name: "John Doe", email: "john@example.com" },
},
},
{
document: createPostMutation,
variables: {
input: { title: "My First Post", content: "Hello World!" },
},
},
]
);Instance method on GraphQLClient for batch operations with client configuration.
/**
* Send multiple GraphQL documents using the client configuration
* @param documents - Array of documents with optional variables
* @param requestHeaders - Optional headers for this batch request
* @returns Promise resolving to array of results
*/
batchRequests<BatchResult extends [Result, ...Result[]], V extends Variables = Variables>(
documents: BatchRequestDocument<V>[],
requestHeaders?: HeadersInit
): Promise<BatchResult>;
/**
* Send batch requests using options object
* @param options - Batch request options
* @returns Promise resolving to array of results
*/
batchRequests<BatchResult extends [Result, ...Result[]], V extends Variables = Variables>(
options: BatchRequestsOptions<V>
): Promise<BatchResult>;
interface BatchRequestsOptions<V extends Variables = Variables> {
documents: BatchRequestDocument<V>[];
requestHeaders?: HeadersInit;
signal?: RequestInit["signal"];
}Usage Examples:
import { GraphQLClient, gql } from "graphql-request";
const client = new GraphQLClient("https://api.example.com/graphql", {
headers: {
authorization: "Bearer TOKEN",
},
});
const query1 = gql`
{
users {
id
name
}
}
`;
const query2 = gql`
{
posts {
id
title
}
}
`;
// Client batch requests
const [usersResult, postsResult] = await client.batchRequests([
{ document: query1 },
{ document: query2 },
]);
console.log("Users:", usersResult.data.users);
console.log("Posts:", postsResult.data.posts);
// Batch requests with per-request headers
const results = await client.batchRequests(
[
{ document: query1 },
{ document: query2 },
],
{
"x-batch-id": "batch-123",
"x-priority": "high",
}
);
// Using options object
const batchResults = await client.batchRequests({
documents: [
{ document: query1 },
{ document: query2 },
],
requestHeaders: {
"x-request-group": "dashboard-data",
},
});Individual document within a batch request.
interface BatchRequestDocument<V extends Variables = Variables> {
/** GraphQL document to execute */
document: RequestDocument;
/** Optional variables for this document */
variables?: V;
}Usage Examples:
import { gql } from "graphql-request";
// Documents with different variable types
const documents: BatchRequestDocument[] = [
{
document: gql`
query GetUser($id: ID!) {
user(id: $id) {
name
}
}
`,
variables: { id: "123" },
},
{
document: gql`
query GetAllPosts {
posts {
title
}
}
`,
// No variables needed
},
{
document: gql`
mutation UpdateUser($id: ID!, $name: String!) {
updateUser(id: $id, name: $name) {
id
name
}
}
`,
variables: { id: "123", name: "Jane Doe" },
},
];Batch requests can provide atomicity for related operations:
import { batchRequests, gql } from "graphql-request";
// Transfer operation requiring multiple mutations
async function transferMoney(fromId: string, toId: string, amount: number) {
const debitMutation = gql`
mutation DebitAccount($accountId: ID!, $amount: Float!) {
debitAccount(id: $accountId, amount: $amount) {
id
balance
success
}
}
`;
const creditMutation = gql`
mutation CreditAccount($accountId: ID!, $amount: Float!) {
creditAccount(id: $accountId, amount: $amount) {
id
balance
success
}
}
`;
try {
const [debitResult, creditResult] = await batchRequests(
"https://banking-api.example.com/graphql",
[
{
document: debitMutation,
variables: { accountId: fromId, amount },
},
{
document: creditMutation,
variables: { accountId: toId, amount },
},
]
);
// Both operations succeed or both fail
if (debitResult.data.debitAccount.success && creditResult.data.creditAccount.success) {
console.log("Transfer completed successfully");
return {
success: true,
fromBalance: debitResult.data.debitAccount.balance,
toBalance: creditResult.data.creditAccount.balance,
};
} else {
throw new Error("Transfer failed - atomicity preserved");
}
} catch (error) {
console.error("Transfer batch failed:", error);
throw error;
}
}Batch requests reduce HTTP overhead for multiple related queries:
import { batchRequests, gql } from "graphql-request";
// Dashboard data loading
async function loadDashboardData(userId: string) {
const profileQuery = gql`
query GetProfile($userId: ID!) {
profile(id: $userId) {
name
avatar
settings
}
}
`;
const notificationsQuery = gql`
query GetNotifications($userId: ID!) {
notifications(userId: $userId, limit: 10) {
id
message
read
createdAt
}
}
`;
const statisticsQuery = gql`
query GetStatistics($userId: ID!) {
statistics(userId: $userId) {
postsCount
followersCount
followingCount
}
}
`;
// Single HTTP request for all dashboard data
const [profileResult, notificationsResult, statisticsResult] = await batchRequests(
"https://api.example.com/graphql",
[
{ document: profileQuery, variables: { userId } },
{ document: notificationsQuery, variables: { userId } },
{ document: statisticsQuery, variables: { userId } },
]
);
return {
profile: profileResult.data.profile,
notifications: notificationsResult.data.notifications,
statistics: statisticsResult.data.statistics,
};
}Handle partial failures in batch operations:
import { batchRequests, gql, ClientError } from "graphql-request";
async function batchWithErrorHandling() {
const queries = [
{
document: gql`{ validQuery { id } }`,
},
{
document: gql`{ invalidQuery { nonExistentField } }`,
},
{
document: gql`{ anotherValidQuery { name } }`,
},
];
try {
const results = await batchRequests("https://api.example.com/graphql", queries);
// Process each result individually
results.forEach((result, index) => {
if (result.data) {
console.log(`Query ${index} succeeded:`, result.data);
} else {
console.log(`Query ${index} failed`);
}
});
return results;
} catch (error) {
if (error instanceof ClientError) {
console.error("Batch request failed:", error.response);
// The entire batch failed - check server logs
} else {
console.error("Network or other error:", error);
}
throw error;
}
}Dynamically build batch requests based on application state:
import { batchRequests, gql } from "graphql-request";
async function loadUserDataConditionally(userId: string, options: {
includeProfile?: boolean;
includePosts?: boolean;
includeFollowers?: boolean;
}) {
const documents: BatchRequestDocument[] = [];
if (options.includeProfile) {
documents.push({
document: gql`
query GetProfile($userId: ID!) {
profile(id: $userId) {
name
bio
avatar
}
}
`,
variables: { userId },
});
}
if (options.includePosts) {
documents.push({
document: gql`
query GetPosts($userId: ID!) {
posts(userId: $userId) {
id
title
content
}
}
`,
variables: { userId },
});
}
if (options.includeFollowers) {
documents.push({
document: gql`
query GetFollowers($userId: ID!) {
followers(userId: $userId) {
id
name
}
}
`,
variables: { userId },
});
}
if (documents.length === 0) {
return {};
}
const results = await batchRequests("https://api.example.com/graphql", documents);
// Build response object based on requested data
const response: any = {};
let resultIndex = 0;
if (options.includeProfile) {
response.profile = results[resultIndex++].data.profile;
}
if (options.includePosts) {
response.posts = results[resultIndex++].data.posts;
}
if (options.includeFollowers) {
response.followers = results[resultIndex++].data.followers;
}
return response;
}type Variables = object;
type RequestDocument = string | DocumentNode;
type BatchVariables = (Variables | undefined)[];