An HTTP/1.1 client, written from scratch for Node.js
—
High-performance HTTP request methods optimized for different use cases, from simple requests to complex streaming scenarios.
Promise-based HTTP requests with the highest performance. Ideal for most HTTP client needs.
/**
* Performs an HTTP request with high performance
* @param url - The URL to request
* @param options - Request configuration options
* @returns Promise resolving to response data
*/
function request(url: string | URL, options?: RequestOptions): Promise<ResponseData>;
interface RequestOptions {
method?: string;
headers?: IncomingHttpHeaders;
body?: BodyInit;
query?: Record<string, any>;
idempotent?: boolean;
blocking?: boolean;
upgrade?: boolean;
headersTimeout?: number;
bodyTimeout?: number;
reset?: boolean;
throwOnError?: boolean;
expectContinue?: boolean;
signal?: AbortSignal;
opaque?: unknown;
}
interface ResponseData {
statusCode: number;
headers: IncomingHttpHeaders;
body: BodyReadable;
trailers: Record<string, string>;
opaque: unknown;
context: {
history: readonly URL[];
};
}Usage Examples:
import { request } from 'undici';
// Simple GET request
const { statusCode, headers, body } = await request('https://api.example.com/users');
const users = await body.json();
// POST request with JSON body
const response = await request('https://api.example.com/users', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
});
// Request with timeout and error handling
try {
const { body } = await request('https://slow-api.example.com/data', {
headersTimeout: 5000,
bodyTimeout: 10000,
throwOnError: true
});
const data = await body.json();
} catch (error) {
console.error('Request failed:', error.message);
}Streaming HTTP requests for handling large payloads efficiently with backpressure support.
/**
* Performs a streaming HTTP request
* @param url - The URL to request
* @param options - Request configuration options
* @param factory - Factory function to create the stream handler
* @returns Promise resolving to stream data
*/
function stream(
url: string | URL,
options: RequestOptions,
factory: StreamFactory
): Promise<StreamData>;
type StreamFactory = (data: StreamFactoryData) => Writable;
interface StreamFactoryData {
statusCode: number;
headers: IncomingHttpHeaders;
opaque: unknown;
}
interface StreamData {
opaque: unknown;
trailers: Record<string, string>;
}Usage Examples:
import { stream } from 'undici';
import { createWriteStream } from 'fs';
// Download large file
await stream('https://example.com/large-file.zip', {}, ({ statusCode, headers }) => {
if (statusCode === 200) {
return createWriteStream('./large-file.zip');
}
throw new Error(`Request failed with status ${statusCode}`);
});
// Stream processing with custom writable
await stream('https://api.example.com/stream-data', {
method: 'GET',
headers: { 'accept': 'application/json' }
}, ({ statusCode }) => {
return new Writable({
write(chunk, encoding, callback) {
// Process each chunk of data
const data = JSON.parse(chunk.toString());
console.log('Received:', data);
callback();
}
});
});Pipeline HTTP requests with Node.js streams for maximum control over data flow.
/**
* Creates a pipeline for streaming HTTP requests
* @param url - The URL to request
* @param options - Request configuration options
* @param handler - Pipeline handler for processing the stream
* @returns Duplex stream for the pipeline
*/
function pipeline(
url: string | URL,
options: PipelineOptions,
handler: PipelineHandler
): Duplex;
interface PipelineOptions extends RequestOptions {
objectMode?: boolean;
}
type PipelineHandler = (data: PipelineHandlerData) => Readable | Transform;
interface PipelineHandlerData {
statusCode: number;
headers: IncomingHttpHeaders;
opaque: unknown;
body: BodyReadable;
}Usage Examples:
import { pipeline } from 'undici';
import { Transform } from 'stream';
import { createReadStream, createWriteStream } from 'fs';
// Upload file with transformation
const uploadStream = pipeline('https://api.example.com/upload', {
method: 'POST',
headers: { 'content-type': 'application/octet-stream' }
}, ({ statusCode }) => {
if (statusCode !== 200) {
throw new Error(`Upload failed: ${statusCode}`);
}
return new Transform({
transform(chunk, encoding, callback) {
// Process upload response
callback(null, chunk);
}
});
});
// Pipe file through upload
createReadStream('./file.txt').pipe(uploadStream).pipe(process.stdout);HTTP CONNECT method for establishing tunnels, typically used for proxying.
/**
* Establishes an HTTP CONNECT tunnel
* @param url - The URL to connect to
* @param options - Connection options
* @returns Promise resolving to connection data
*/
function connect(url: string | URL, options?: ConnectOptions): Promise<ConnectData>;
interface ConnectOptions {
headers?: IncomingHttpHeaders;
signal?: AbortSignal;
opaque?: unknown;
}
interface ConnectData {
statusCode: number;
headers: IncomingHttpHeaders;
socket: Duplex;
opaque: unknown;
}Usage Examples:
import { connect } from 'undici';
// Establish CONNECT tunnel through proxy
const { socket, statusCode } = await connect('https://proxy.example.com:8080', {
headers: {
'proxy-authorization': 'Basic ' + Buffer.from('user:pass').toString('base64')
}
});
if (statusCode === 200) {
// Use socket for tunneled communication
socket.write('GET /api/data HTTP/1.1\r\nHost: api.example.com\r\n\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
}HTTP protocol upgrade requests for switching protocols (e.g., WebSocket handshake).
/**
* Performs an HTTP protocol upgrade
* @param url - The URL to upgrade
* @param options - Upgrade options
* @returns Promise resolving to upgrade data
*/
function upgrade(url: string | URL, options?: UpgradeOptions): Promise<UpgradeData>;
interface UpgradeOptions {
headers?: IncomingHttpHeaders;
protocol?: string;
signal?: AbortSignal;
opaque?: unknown;
}
interface UpgradeData {
headers: IncomingHttpHeaders;
socket: Duplex;
opaque: unknown;
}Usage Examples:
import { upgrade } from 'undici';
// WebSocket handshake
const { socket, headers } = await upgrade('ws://localhost:3000/socket', {
headers: {
'upgrade': 'websocket',
'connection': 'upgrade',
'sec-websocket-key': 'dGhlIHNhbXBsZSBub25jZQ==',
'sec-websocket-version': '13'
}
});
// Handle WebSocket communication
socket.on('data', (data) => {
console.log('WebSocket data:', data);
});type BodyInit =
| ArrayBuffer
| AsyncIterable<Uint8Array>
| Blob
| FormData
| Iterable<Uint8Array>
| NodeJS.ArrayBufferView
| URLSearchParams
| null
| string;
interface BodyReadable extends Readable {
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
bytes(): Promise<Uint8Array>;
json(): Promise<any>;
text(): Promise<string>;
}type IncomingHttpHeaders = Record<string, string | string[]>;
type OutgoingHttpHeaders = Record<string, string | string[] | number>;Install with Tessl CLI
npx tessl i tessl/npm-undici