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.
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 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'
}
});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>;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);
}
});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 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}`
}
});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 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(),
},
}));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
]);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;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;