CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-mockttp

Mock HTTP server for testing HTTP clients and stubbing webservices

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

response-actions.mddocs/

Response Actions

Comprehensive response generation system supporting fixed responses, dynamic callbacks, file streaming, request forwarding, and connection manipulation for simulating various server behaviors.

Capabilities

Fixed Responses

Simple static responses with predefined status, body, and headers.

interface RequestRuleBuilder {
  /**
   * Send a fixed response with specified status code, body, and optional headers/trailers.
   * Body can be string, Buffer, or object (automatically JSON-serialized).
   */
  thenReply(
    status: number, 
    data?: string | Buffer | object, 
    headers?: Headers, 
    trailers?: Trailers
  ): Promise<MockedEndpoint>;
  
  /**
   * Send a fixed response with specified status code, custom status message, body, and optional headers/trailers.
   */
  thenReply(
    status: number,
    statusMessage: string,
    data: string | Buffer,
    headers?: Headers,
    trailers?: Trailers
  ): Promise<MockedEndpoint>;
  
  /**
   * Send a JSON response with specified status code and object data.
   * Automatically sets Content-Type to application/json.
   */
  thenJson(
    status: number, 
    data: object, 
    headers?: Headers
  ): Promise<MockedEndpoint>;
  
  /**
   * Send response from a file with specified status and optional headers.
   */
  thenFromFile(
    status: number, 
    filePath: string, 
    headers?: Headers
  ): Promise<MockedEndpoint>;
  
  /**
   * Send response from a file with specified status, custom status message, and optional headers.
   */
  thenFromFile(
    status: number,
    statusMessage: string,
    filePath: string, 
    headers?: Headers
  ): Promise<MockedEndpoint>;
}

interface Headers {
  [key: string]: undefined | string | string[];
}

interface Trailers {
  [key: string]: undefined | string | string[];
}

Usage Examples:

import { getLocal } from "mockttp";

const mockServer = getLocal();
await mockServer.start();

// Simple text response
await mockServer.forGet("/api/hello")
  .thenReply(200, "Hello, World!");

// JSON response with custom headers
await mockServer.forGet("/api/users")
  .thenJson(200, 
    { users: [{ id: 1, name: "Alice" }] },
    { "X-Total-Count": "1" }
  );

// Binary response with Buffer
const imageBuffer = Buffer.from("binary-image-data");
await mockServer.forGet("/api/avatar.png")
  .thenReply(200, imageBuffer, {
    "Content-Type": "image/png",
    "Cache-Control": "max-age=3600"
  });

// Response with trailers (HTTP/1.1 chunked encoding)
await mockServer.forGet("/api/stream")
  .thenReply(200, "Response body", 
    { "Transfer-Encoding": "chunked" },
    { "X-Checksum": "abc123" }
  );

// File response
await mockServer.forGet("/download/file.pdf")
  .thenFromFile(200, "/path/to/file.pdf", {
    "Content-Type": "application/pdf",
    "Content-Disposition": "attachment; filename=file.pdf"
  });

Dynamic Responses

Generate responses dynamically based on request content using callback functions.

interface RequestRuleBuilder {
  /**
   * Generate response dynamically using a callback function.
   * Callback receives the completed request and returns response configuration.
   */
  thenCallback(
    callback: (request: CompletedRequest) => CallbackResponseResult | Promise<CallbackResponseResult>
  ): Promise<MockedEndpoint>;
}

interface CallbackResponseResult {
  statusCode?: number;
  statusMessage?: string;
  headers?: Headers;
  trailers?: Trailers;
  body?: string | Buffer | Uint8Array | object;
  json?: object;
}

interface CompletedRequest {
  id: string;
  matchedRuleId?: string;
  protocol: string;
  httpVersion: string;
  method: string;
  url: string;
  path: string;
  headers: Headers;
  body: CompletedBody;
  timingEvents: TimingEvents;
  tags: string[];
}

interface CompletedBody {
  buffer: Buffer;
  getDecodedBuffer(): Promise<Buffer | undefined>;
  getText(): Promise<string | undefined>;
  getJson(): Promise<object | undefined>;
  getFormData(): Promise<{[key: string]: string | string[] | undefined} | undefined>;
}

Usage Examples:

import { getLocal } from "mockttp";

const mockServer = getLocal();
await mockServer.start();

// Echo request data back
await mockServer.forPost("/api/echo")
  .thenCallback(async (request) => {
    const body = await request.body.getText();
    return {
      statusCode: 200,
      headers: { "Content-Type": "text/plain" },
      body: `Echo: ${body}`
    };
  });

// Dynamic JSON response based on request
await mockServer.forGet("/api/user/*")
  .thenCallback(async (request) => {
    const userId = request.path.split('/').pop();
    const userAgent = request.headers['user-agent'] || 'unknown';
    
    return {
      json: {
        id: userId,
        userAgent: userAgent,
        timestamp: new Date().toISOString()
      }
    };
  });

// Conditional response based on headers
await mockServer.forPost("/api/auth")
  .thenCallback(async (request) => {
    const authHeader = request.headers.authorization;
    
    if (authHeader === 'Bearer valid-token') {
      return { statusCode: 200, json: { authenticated: true } };
    } else {
      return { 
        statusCode: 401, 
        json: { error: "Invalid token" },
        headers: { "WWW-Authenticate": "Bearer" }
      };
    }
  });

// Process form data
await mockServer.forPost("/api/contact")
  .thenCallback(async (request) => {
    const formData = await request.body.getFormData();
    const email = formData?.email;
    
    if (email && typeof email === 'string') {
      return {
        statusCode: 200,
        json: { message: `Thank you, ${email}!` }
      };
    } else {
      return {
        statusCode: 400,
        json: { error: "Email required" }
      };
    }
  });

Stream Responses

Send responses from readable streams for large files or real-time data.

interface RequestRuleBuilder {
  /**
   * Send response from a readable stream.
   * Useful for large files or streaming data.
   */
  thenStream(
    status: number, 
    stream: stream.Readable, 
    headers?: Headers
  ): Promise<MockedEndpoint>;
}

Usage Examples:

import { getLocal } from "mockttp";
import * as fs from "fs";
import { Readable } from "stream";

const mockServer = getLocal();
await mockServer.start();

// Stream file response
await mockServer.forGet("/api/large-file")
  .thenStream(200, 
    fs.createReadStream("/path/to/large-file.json"),
    { "Content-Type": "application/json" }
  );

// Stream generated data
await mockServer.forGet("/api/live-data")
  .thenStream(200, 
    Readable.from(generateDataStream()),
    { 
      "Content-Type": "text/plain",
      "Transfer-Encoding": "chunked"
    }
  );

async function* generateDataStream() {
  for (let i = 0; i < 1000; i++) {
    yield `Data chunk ${i}\n`;
    await new Promise(resolve => setTimeout(resolve, 10));
  }
}

Request Forwarding

Forward requests to real servers with optional transformations.

interface RequestRuleBuilder {
  /**
   * Forward request to the original target server.
   * Useful for selective mocking while allowing real traffic through.
   */
  thenPassThrough(options?: PassThroughStepOptions): Promise<MockedEndpoint>;
  
  /**
   * Forward request to a specific target URL.
   * Enables request proxying and redirection.
   */
  thenForwardTo(
    target: string, 
    options?: PassThroughStepOptions
  ): Promise<MockedEndpoint>;
}

interface PassThroughStepOptions {
  /**
   * Transformations to apply to outgoing request.
   */
  transformRequest?: RequestTransform;
  
  /**
   * Transformations to apply to incoming response.
   */
  transformResponse?: ResponseTransform;
  
  /**
   * Custom DNS lookup function for request destination.
   */
  lookupOptions?: PassThroughLookupOptions;
  
  /**
   * Connection options for upstream request.
   */
  connectionOptions?: PassThroughStepConnectionOptions;
  
  /**
   * Initial transforms before forwarding.
   */
  initialTransforms?: PassThroughInitialTransforms;
  
  /**
   * Forwarding configuration options.
   */
  forwardingOptions?: ForwardingOptions;
}

interface RequestTransform {
  updateHeaders?: (headers: Headers) => Headers;
  updateBody?: (body: Buffer) => Buffer | Promise<Buffer>;
}

interface ResponseTransform {
  updateStatus?: (status: number) => number;
  updateHeaders?: (headers: Headers) => Headers;
  updateBody?: (body: Buffer) => Buffer | Promise<Buffer>;
}

Usage Examples:

import { getLocal } from "mockttp";

const mockServer = getLocal();
await mockServer.start();

// Pass through to original server
await mockServer.forGet("/api/external")
  .thenPassThrough();

// Forward to different server
await mockServer.forPost("/api/proxy")
  .thenForwardTo("https://api.example.com/v1/data");

// Forward with request transformation
await mockServer.forPost("/api/transform")
  .thenForwardTo("https://api.example.com/webhook", {
    transformRequest: {
      updateHeaders: (headers) => ({
        ...headers,
        'X-Forwarded-By': 'mockttp',
        'Authorization': 'Bearer secret-token'
      })
    }
  });

// Forward with response transformation
await mockServer.forGet("/api/filtered")
  .thenPassThrough({
    transformResponse: {
      updateStatus: (status) => status === 404 ? 200 : status,
      updateBody: async (body) => {
        const data = JSON.parse(body.toString());
        return Buffer.from(JSON.stringify({
          ...data,
          filtered: true,
          timestamp: Date.now()
        }));
      }
    }
  });

Connection Control

Control connection behavior for testing network conditions and error scenarios.

interface RequestRuleBuilder {
  /**
   * Close the connection immediately without sending a response.
   * Simulates server crashes or network failures.
   */
  thenCloseConnection(): Promise<MockedEndpoint>;
  
  /**
   * Reset the connection with a TCP RST packet.
   * Simulates aggressive connection termination.
   */
  thenResetConnection(): Promise<MockedEndpoint>;
  
  /**
   * Hold the connection open indefinitely without responding.
   * Simulates server timeouts and hanging connections.
   */
  thenTimeout(): Promise<MockedEndpoint>;
}

Usage Examples:

import { getLocal } from "mockttp";

const mockServer = getLocal();
await mockServer.start();

// Simulate server crash
await mockServer.forPost("/api/unreliable")
  .thenCloseConnection();

// Simulate connection reset
await mockServer.forGet("/api/forbidden")
  .thenResetConnection();

// Simulate slow/hanging server
await mockServer.forGet("/api/slow")
  .thenTimeout();

// Combined with execution control for flaky behavior
await mockServer.forPost("/api/flaky")
  .twice()
  .thenCloseConnection();

// Then add a fallback rule
await mockServer.forPost("/api/flaky")
  .thenReply(200, { success: true });

Response Timing

Add delays to simulate network latency and slow servers.

interface RequestRuleBuilder {
  /**
   * Add a delay before processing the next step.
   * Can be chained with other response actions.
   */
  delay(ms: number): this;
}

Usage Examples:

import { getLocal } from "mockttp";

const mockServer = getLocal();
await mockServer.start();

// Slow response simulation
await mockServer.forGet("/api/slow")
  .delay(2000) // 2 second delay
  .thenReply(200, { data: "finally!" });

// Variable delay with callback
await mockServer.forGet("/api/variable")
  .delay(Math.random() * 1000) // 0-1 second random delay
  .thenJson(200, { timestamp: Date.now() });

// Delayed forwarding
await mockServer.forPost("/api/slow-proxy")
  .delay(500)
  .thenForwardTo("https://slow-api.example.com/endpoint");

JSON-RPC Responses

Specialized responses for JSON-RPC protocol support.

interface RequestRuleBuilder {
  /**
   * Send a JSON-RPC success response with the given result.
   * Automatically formats with jsonrpc: "2.0" and proper structure.
   */
  thenSendJsonRpcResult(
    result: any, 
    id?: string | number
  ): Promise<MockedEndpoint>;
  
  /**
   * Send a JSON-RPC error response with the given error details.
   * Automatically formats with jsonrpc: "2.0" and proper error structure.
   */
  thenSendJsonRpcError(
    error: {code: number, message: string, data?: any}, 
    id?: string | number
  ): Promise<MockedEndpoint>;
}

Usage Examples:

import { getLocal } from "mockttp";

const mockServer = getLocal();
await mockServer.start();

// JSON-RPC success response
await mockServer.forJsonRpcRequest({ method: "getUser" })
  .thenSendJsonRpcResult({
    id: 123,
    name: "Alice",
    email: "alice@example.com"
  });

// JSON-RPC error response
await mockServer.forJsonRpcRequest({ method: "deleteUser" })
  .thenSendJsonRpcError({
    code: -32602,
    message: "Invalid params",
    data: { required: ["id"] }
  });

// Dynamic JSON-RPC with callback
await mockServer.forJsonRpcRequest()
  .thenCallback(async (request) => {
    const body = await request.body.getJson() as any;
    
    if (body.method === "add") {
      const [a, b] = body.params;
      return {
        json: {
          jsonrpc: "2.0",
          result: a + b,
          id: body.id
        }
      };
    } else {
      return {
        json: {
          jsonrpc: "2.0",
          error: {
            code: -32601,
            message: "Method not found"
          },
          id: body.id
        }
      };
    }
  });

Response Chaining

Multiple response actions can be chained for complex scenarios:

import { getLocal } from "mockttp";

const mockServer = getLocal();
await mockServer.start();

// Delayed response with custom headers
await mockServer.forGet("/api/complex")
  .delay(1000)
  .thenReply(200, "Success", {
    "X-Processing-Time": "1000",
    "X-Server": "mockttp"
  });

All response methods return Promise<MockedEndpoint> which provides access to the created rule for monitoring and testing.

docs

certificate-management.md

event-monitoring.md

http-request-mocking.md

index.md

mock-server-setup.md

response-actions.md

websocket-mocking.md

tile.json