or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

caching.mdcore-client.mderror-handling.mdindex.mdlink-system.mdmasking.mdreact-hooks.mdtesting.mdutilities.md
tile.json

link-system.mddocs/

Link System

Modular transport and middleware system for GraphQL operations. The Apollo Link system provides customizable request/response processing with support for multiple transports, middleware composition, and request transformation.

Capabilities

ApolloLink Base Class

Abstract base class for all Apollo Link implementations providing request handling and composition.

/**
 * Abstract base class for Apollo Link implementations
 * Handles GraphQL operations with customizable request/response processing
 */
abstract class ApolloLink {
  /**
   * Process a GraphQL operation
   * @param operation - Operation to process
   * @returns Observable of fetch results or null
   */
  abstract request(operation: Operation): Observable<FetchResult> | null;
  
  /**
   * Combine multiple links into a single link
   * @param links - Array of links or request handlers
   * @returns Combined link
   */
  static from(links: (ApolloLink | RequestHandler)[]): ApolloLink;
  
  /**
   * Split requests between links based on condition
   * @param test - Function to determine which link to use
   * @param left - Link for truthy test results
   * @param right - Link for falsy test results
   * @returns Conditional link
   */
  static split(
    test: (op: Operation) => boolean,
    left: ApolloLink | RequestHandler,
    right: ApolloLink | RequestHandler
  ): ApolloLink;
  
  /**
   * Concatenate this link with another
   * @param next - Next link in chain
   * @returns Concatenated link
   */
  concat(next: ApolloLink | RequestHandler): ApolloLink;
}

HTTP Link

HTTP transport implementation for GraphQL over HTTP/HTTPS.

/**
 * HTTP transport link for GraphQL operations
 * Sends GraphQL operations over HTTP/HTTPS with full configuration support
 */
class HttpLink extends ApolloLink {
  constructor(options?: HttpOptions);
}

/**
 * Create HTTP link with configuration
 * @param options - HTTP transport options
 * @returns Configured HTTP link
 */
function createHttpLink(options?: HttpOptions): ApolloLink;

interface HttpOptions {
  /** GraphQL endpoint URI */
  uri?: string | UriFunction;
  /** Fetch implementation */
  fetch?: typeof fetch;
  /** HTTP headers */
  headers?: Record<string, string>;
  /** Include credentials in requests */
  includeCredentials?: boolean;
  /** Custom fetch options */
  fetchOptions?: RequestInit | FetchOptionsFunction;
  /** Use GET for queries */
  useGETForQueries?: boolean;
  /** Include unused variables */
  includeUnusedVariables?: boolean;
}

Usage Example:

import { createHttpLink } from "@apollo/client/link/http";

const httpLink = createHttpLink({
  uri: 'https://api.example.com/graphql',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  fetchOptions: {
    credentials: 'include'
  }
});

Link Composition

Utility functions for combining and composing links.

/**
 * Combine multiple links sequentially
 * @param links - Array of links to combine
 * @returns Combined link chain
 */
function from(links: (ApolloLink | RequestHandler)[]): ApolloLink;

/**
 * Concatenate two links
 * @param first - First link in chain
 * @param second - Second link in chain  
 * @returns Concatenated link
 */
function concat(first: ApolloLink | RequestHandler, second: ApolloLink | RequestHandler): ApolloLink;

/**
 * Conditionally route requests to different links
 * @param test - Predicate function
 * @param left - Link for truthy results
 * @param right - Link for falsy results
 * @returns Conditional routing link
 */
function split(
  test: (operation: Operation) => boolean,
  left: ApolloLink | RequestHandler,
  right: ApolloLink | RequestHandler
): ApolloLink;

/**
 * Empty link that returns empty observable
 * @returns Empty link
 */
function empty(): ApolloLink;

/**
 * Execute operation through link chain
 * @param link - Link to execute
 * @param operation - Operation to execute
 * @returns Observable of results
 */
function execute(link: ApolloLink, operation: GraphQLRequest): Observable<FetchResult>;

Error Link

Handle GraphQL and network errors with custom logic and retry capabilities.

/**
 * Error handling link for custom error logic and retry functionality
 * Provides error interception and handling capabilities
 */
class ErrorLink extends ApolloLink {
  constructor(errorHandler: ErrorLink.ErrorHandler);
}

interface ErrorLink.ErrorHandler {
  (options: ErrorLink.ErrorHandlerOptions): Observable<FetchResult> | void;
}

interface ErrorLink.ErrorHandlerOptions {
  /** The error that occurred */
  error: ErrorLike;
  /** Raw GraphQL result (if available) */
  result?: FetchResult;
  /** The operation that caused the error */
  operation: Operation;
  /** Function to retry the operation */
  forward: ApolloLink.ForwardFunction;
}

Usage Example:

import { ErrorLink } from "@apollo/client/link/error";
import { CombinedGraphQLErrors, CombinedProtocolErrors } from "@apollo/client/errors";

const errorLink = new ErrorLink(({ error, operation, forward }) => {
  if (CombinedGraphQLErrors.is(error)) {
    error.errors.forEach(({ message, locations, path }) =>
      console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`)
    );
  } else if (CombinedProtocolErrors.is(error)) {
    error.errors.forEach(({ message, extensions }) =>
      console.log(`[Protocol error]: Message: ${message}, Extensions: ${JSON.stringify(extensions)}`)
    );
  } else {
    console.error(`[Network error]: ${error}`);
  }
  
  // Optionally retry the operation
  if (shouldRetry(error)) {
    return forward(operation);
  }
});

Retry Link

Automatically retry failed GraphQL operations with configurable delay and attempt strategies.

/**
 * Retry link for automatic operation retries with configurable strategies
 * Handles transient failures with exponential backoff and jitter
 */
class RetryLink extends ApolloLink {
  constructor(options?: RetryLink.Options);
}

interface RetryLink.Options {
  /** Delay configuration between retries */
  delay?: {
    initial?: number;
    max?: number;
    jitter?: boolean;
  } | number;
  /** Attempt configuration */
  attempts?: {
    max?: number;
    retryIf?: (error: any, operation: Operation) => boolean;
  } | number;
}

Usage Example:

import { RetryLink } from "@apollo/client/link/retry";

const retryLink = new RetryLink({
  delay: {
    initial: 300,
    max: Infinity,
    jitter: true
  },
  attempts: {
    max: 5,
    retryIf: (error, _operation) => !!error && error.networkError
  }
});

Batch HTTP Link

Batch multiple GraphQL operations into single HTTP requests for improved performance.

/**
 * Batch HTTP link for combining multiple operations into single requests
 * Reduces network overhead by batching operations within time windows
 */
class BatchHttpLink extends ApolloLink {
  constructor(options?: BatchHttpLink.Options);
}

interface BatchHttpLink.Options extends HttpOptions {
  /** Maximum number of operations per batch */
  batchMax?: number;
  /** Time window for batching operations (ms) */
  batchInterval?: number;
  /** Custom function to determine batch grouping */
  batchKey?: (operation: Operation) => string;
}

Usage Example:

import { BatchHttpLink } from "@apollo/client/link/batch-http";

const batchLink = new BatchHttpLink({
  uri: 'https://api.example.com/graphql',
  batchMax: 5,
  batchInterval: 20,
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

Context Link

Set operation context for downstream links in the chain.

/**
 * Context link for setting operation context dynamically
 * Allows modification of operation context based on runtime conditions
 */
class ContextLink extends ApolloLink {
  constructor(setContext: (operation: Operation) => Record<string, any> | Promise<Record<string, any>>);
}

Usage Example:

import { setContext } from "@apollo/client/link/context";

const contextLink = setContext(async (_, { headers }) => {
  const token = await getAuthToken();
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    }
  };
});

WebSocket Link

WebSocket transport for GraphQL subscriptions and real-time operations.

/**
 * WebSocket link for GraphQL subscriptions and real-time operations
 * Provides persistent connection for streaming GraphQL operations
 */
class WebSocketLink extends ApolloLink {
  constructor(options: WebSocketLink.Configuration);
}

interface WebSocketLink.Configuration {
  /** WebSocket endpoint URI */
  uri: string;
  /** WebSocket connection options */
  options?: {
    reconnect?: boolean;
    connectionParams?: Record<string, any> | (() => Record<string, any>);
    lazy?: boolean;
  };
  /** WebSocket implementation */
  webSocketImpl?: any;
}

Usage Example:

import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";

const wsLink = new GraphQLWsLink(createClient({
  url: 'wss://api.example.com/graphql',
  connectionParams: {
    authToken: getAuthToken(),
  },
}));

Complete Link Chain Example

import { from, createHttpLink, split } from "@apollo/client/link";
import { ErrorLink } from "@apollo/client/link/error";
import { RetryLink } from "@apollo/client/link/retry";
import { BatchHttpLink } from "@apollo/client/link/batch-http";
import { setContext } from "@apollo/client/link/context";
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
import { getMainDefinition } from "@apollo/client/utilities";

// Authentication context
const authLink = setContext(async (_, { headers }) => {
  const token = await getAuthToken();
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    }
  };
});

// Error handling with retry logic
const errorLink = new ErrorLink(({ error, operation, forward }) => {
  console.error('GraphQL Error:', error);
  
  // Retry auth errors
  if (error.message.includes('Unauthorized')) {
    return refreshAuthToken().then(() => forward(operation));
  }
});

// Retry transient failures
const retryLink = new RetryLink({
  delay: {
    initial: 300,
    max: Infinity,
    jitter: true
  },
  attempts: {
    max: 3,
    retryIf: (error, _operation) => !!error && !error.message?.includes('Unauthorized')
  }
});

// Batch HTTP for queries and mutations
const batchHttpLink = new BatchHttpLink({
  uri: 'https://api.example.com/graphql',
  batchMax: 10,
  batchInterval: 20
});

// WebSocket for subscriptions
const wsLink = new GraphQLWsLink(createClient({
  url: 'wss://api.example.com/graphql',
  connectionParams: () => ({
    authToken: getStoredToken(),
  }),
}));

// Split between HTTP and WebSocket based on operation type
const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  batchHttpLink
);

// Combine all links into final chain
const link = from([
  authLink,
  errorLink,
  retryLink,
  splitLink
]);

HTTP Utilities

function checkFetcher(fetch: typeof fetch): void;
function createSignalIfSupported(): AbortSignal | undefined;
function parseAndCheckHttpResponse(response: Response): Promise<any>;
function selectURI(operation: Operation, fallbackURI?: string): string;
function rewriteURIForGET(chosenURI: string, body: Body): string;

Types

interface Operation {
  query: DocumentNode;
  variables?: Record<string, any>;
  operationName?: string;
  extensions?: Record<string, any>;
  setContext: (context: DefaultContext) => void;
  getContext: () => DefaultContext;
}

interface FetchResult<TData = Record<string, any>, TContext = Record<string, any>, TExtensions = Record<string, any>> {
  data?: TData | null;
  extensions?: TExtensions;
  context?: TContext;
  errors?: readonly GraphQLError[];
}

interface GraphQLRequest {
  query: DocumentNode;
  variables?: Record<string, any>;
  operationName?: string;
  context?: DefaultContext;
  extensions?: Record<string, any>;
}

type RequestHandler = (operation: Operation) => Observable<FetchResult> | null;
type UriFunction = (operation: Operation) => string;
type FetchOptionsFunction = (operation: Operation) => RequestInit;