GraphQL Tools Links provides Apollo GraphQL link utilities specifically designed for server-side environments. It enables creating HTTP links that work seamlessly with GraphQL tools and Apollo Client in Node.js applications, with specialized support for variable resolution, file uploads, and executor integration.
npm install @graphql-tools/linksimport {
createServerHttpLink,
AwaitVariablesLink,
linkToExecutor,
GraphQLUpload
} from "@graphql-tools/links";For CommonJS:
const {
createServerHttpLink,
AwaitVariablesLink,
linkToExecutor,
GraphQLUpload
} = require("@graphql-tools/links");import { createServerHttpLink, linkToExecutor, GraphQLUpload } from "@graphql-tools/links";
import { stitchSchemas } from "@graphql-tools/stitch";
// Create a server-compatible HTTP link with file upload support
const link = createServerHttpLink({
uri: "http://localhost:4000/graphql",
// Additional apollo-upload-client options supported
});
// Convert the link to a GraphQL executor for use with schema stitching
const executor = linkToExecutor(link);
// Use in schema stitching
const schema = stitchSchemas({
subschemas: [
{
schema: remoteSchema,
executor: executor,
}
],
resolvers: {
Upload: GraphQLUpload, // Add upload scalar support
},
});GraphQL Tools Links is built around four key components that work together:
createServerHttpLink() creates Apollo Client links optimized for server environmentsAwaitVariablesLink handles asynchronous variable resolution before forwarding operationslinkToExecutor() converts Apollo Links to GraphQL Tools executors for schema stitchingGraphQLUpload scalar handles file uploads in GraphQL schemasThe package uses Node.js-specific modules (node-fetch, form-data) and is designed exclusively for server-side usage.
Creates a server-compatible HTTP link with integrated file upload support and asynchronous variable resolution.
/**
* Creates a server-compatible HTTP link with file upload support
* @param options - Configuration options for apollo-upload-client
* @returns Apollo Link configured for server-side usage
*/
declare const createServerHttpLink: (options: any) => ApolloLink;Usage Example:
import { createServerHttpLink } from "@graphql-tools/links";
const link = createServerHttpLink({
uri: "http://localhost:4000/graphql",
headers: {
authorization: "Bearer token123",
},
// All apollo-upload-client options are supported
});Apollo Link that resolves Promise-based variables before forwarding operations to the next link in the chain.
/**
* Apollo Link that resolves Promise-based variables before forwarding operations
*/
declare class AwaitVariablesLink extends ApolloLink {
/**
* Processes GraphQL operations, resolving any Promise values in variables
* @param operation - GraphQL operation with potentially async variables
* @param forward - Next link in the Apollo Link chain
* @returns Observable of the operation result
*/
request(
operation: Operation,
forward: NextLink
): Observable<FetchResult>;
}Usage Example:
import { AwaitVariablesLink } from "@graphql-tools/links";
import { from, createHttpLink, execute } from "@apollo/client";
const awaitLink = new AwaitVariablesLink();
const httpLink = createHttpLink({ uri: "/graphql" });
const link = from([awaitLink, httpLink]);
// Now variables with Promise values will be resolved automatically
const result = await execute(link, {
query: MY_QUERY,
variables: {
userId: Promise.resolve("user-123"),
metadata: Promise.resolve({ timestamp: Date.now() }),
},
});Converts Apollo Links to GraphQL Tools executors, enabling integration with schema stitching and other GraphQL Tools utilities.
/**
* Converts Apollo Link to GraphQL Tools Executor
* @param link - Apollo Link to convert
* @returns Executor function compatible with GraphQL Tools
*/
declare function linkToExecutor(link: ApolloLink): Executor;
/**
* Executor function type from GraphQL Tools with full generic signature
*/
type Executor<TReturn = any, TArgs extends Record<string, any> = any, TContext = any> = (
request: ExecutionRequest<TArgs, TContext>
) => Promise<ExecutionResult<TReturn>> | AsyncIterable<ExecutionResult<TReturn>>;Usage Example:
import { linkToExecutor, createServerHttpLink } from "@graphql-tools/links";
import { stitchSchemas } from "@graphql-tools/stitch";
const httpLink = createServerHttpLink({
uri: "http://remote-service:4000/graphql",
});
const executor = linkToExecutor(httpLink);
const stitchedSchema = stitchSchemas({
subschemas: [
{
schema: remoteSchema,
executor: executor, // Use the converted executor
}
],
});GraphQL scalar type for handling file uploads, compatible with both graphql-upload v9 and v10 formats.
/**
* GraphQL scalar type for handling file uploads
* Supports both graphql-upload v9 and v10 formats
*/
declare const GraphQLUpload: GraphQLScalarType;Usage Example:
import { GraphQLUpload } from "@graphql-tools/links";
import { makeExecutableSchema } from "@graphql-tools/schema";
const typeDefs = `
scalar Upload
type Mutation {
uploadFile(file: Upload!): String
}
`;
const resolvers = {
Upload: GraphQLUpload,
Mutation: {
uploadFile: async (parent, { file }) => {
const { createReadStream, filename } = await file;
// Handle file upload
return filename;
},
},
};
const schema = makeExecutableSchema({ typeDefs, resolvers });/**
* Apollo Client types used throughout the package
*/
import type {
ApolloLink,
Operation,
NextLink,
Observable,
FetchResult,
} from "@apollo/client";
/**
* GraphQL Tools types for executor integration
*/
import type {
ExecutionRequest,
ExecutionResult,
Executor,
} from "@graphql-tools/utils";
/**
* GraphQL scalar type from graphql library
*/
import type { GraphQLScalarType } from "graphql";The package handles several error scenarios:
GraphQLUpload.parseLiteral() throws a GraphQLError when literal values are used (not supported for uploads)AwaitVariablesLink catches Promise rejections and forwards them to the observer's error handler@apollo/client: ^3graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0With Schema Stitching:
import { stitchSchemas } from "@graphql-tools/stitch";
import { createServerHttpLink, linkToExecutor, GraphQLUpload } from "@graphql-tools/links";
const schema = stitchSchemas({
subschemas: [
{
schema: remoteSchema,
executor: linkToExecutor(createServerHttpLink({ uri: remoteUrl })),
}
],
resolvers: {
Upload: GraphQLUpload,
},
});With Express and File Uploads:
import express from "express";
import graphqlUploadExpress from "graphql-upload/graphqlUploadExpress.mjs";
import { GraphQLUpload } from "@graphql-tools/links";
const app = express();
app.use(graphqlUploadExpress()); // Handle multipart uploads
// Use GraphQLUpload in your schema resolvers