or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

batch-operations.mderror-handling.mdgraphql-client.mdindex.mdraw-requests.mdstatic-functions.md
tile.json

batch-operations.mddocs/

Batch Operations

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.

Capabilities

Batch Requests Function

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!" },
      },
    },
  ]
);

GraphQL Client Batch Requests Method

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",
  },
});

Batch Document Structure

Batch Request Document

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" },
  },
];

Use Cases and Best Practices

Atomic Operations

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;
  }
}

Performance Optimization

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,
  };
}

Error Handling in Batches

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;
  }
}

Conditional Batching

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;
}

Supporting Types

type Variables = object;
type RequestDocument = string | DocumentNode;

type BatchVariables = (Variables | undefined)[];