npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

effect-http-mock

v0.1.0

Published

HTTP client mocking library for Effect-based applications with record & replay capabilities

Readme

MockHTTP

A powerful HTTP client mocking library for Effect-based applications that captures real HTTP responses and replays them during tests. Perfect for creating reliable, deterministic tests without hitting external services.

Features

  • 🎭 Record & Replay: Capture real HTTP responses and replay them in tests
  • 🚀 Effect Integration: Built on top of Effect and @effect/platform
  • 💾 File-based Storage: Responses stored as files for easy versioning and inspection
  • 🔄 Automatic Recording: makeWithRecord automatically captures missing responses
  • 🎯 Type-safe: Full TypeScript support with Effect's type system
  • 🧪 Test Framework Agnostic: Works with any test runner (Bun, Jest, Vitest, etc.)

Installation

bun install mockhttp

Quick Start

Basic Usage - Pure Mock Mode

Use pre-recorded responses only. Fails if response not found:

import { MockHttpClient } from "mockhttp";
import { HttpClient } from "@effect/platform";
import { Effect, Layer } from "effect";
import { BunFileSystem } from "@effect/platform-bun";

// Create a mock client layer
const mockLayer = MockHttpClient.make("./.mock_responses").pipe(
  Layer.provide(BunFileSystem.layer)
);

// Use in your tests
const program = Effect.gen(function* () {
  const client = yield* HttpClient.HttpClient;
  const response = yield* client.get("https://api.example.com/users");
  return yield* response.json;
});

// Run with mock
const result = await program.pipe(
  Effect.provide(mockLayer),
  Effect.runPromise
);

Record & Replay Mode

Automatically records responses for missing mocks:

import { FetchHttpClient } from "@effect/platform";

const mockWithRecordLayer = MockHttpClient.makeWithRecord("./.mock_responses").pipe(
  Layer.provide(BunFileSystem.layer),
  Layer.provide(FetchHttpClient.layer) // Real client for recording
);

// First run: makes real HTTP request and saves response
// Subsequent runs: uses saved response
const program = Effect.gen(function* () {
  const client = yield* HttpClient.HttpClient;
  const response = yield* client.get("https://httpbin.org/get");
  return yield* response.json;
});

How It Works

Response Storage

MockHTTP stores HTTP responses as files in the specified directory. Each request is uniquely identified by:

  • HTTP method
  • Full URL (including query parameters)

The filename is a base64url encoding of "METHOD URL" with .http extension.

Response Format

Responses are stored in raw HTTP format:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123

{"data": "response body"}

Serialization Process

  1. Capturing: When a real response is received, it's serialized with status line, headers, and body
  2. Storage: The serialized response is saved to disk using Effect's FileSystem
  3. Replay: When the same request is made, the response is deserialized and returned

API Reference

MockHttpClient.make(dir?: string)

Creates a pure mock client that only uses pre-recorded responses.

  • dir: Directory to store/read responses (default: ./.mock_responses)
  • Returns: Layer<HttpClient.HttpClient, never, FileSystem.FileSystem>

MockHttpClient.makeWithRecord(dir?: string)

Creates a recording mock client that captures missing responses.

  • dir: Directory to store/read responses (default: ./.mock_responses)
  • Returns: Layer<HttpClient.HttpClient, never, FileSystem.FileSystem>
  • Requires: An actual HttpClient layer (like FetchHttpClient) for recording

Response Serialization

// Serialize a response to wire format
const serializeResponse: (
  res: HttpClientResponse
) => Effect<Uint8Array, ResponseError, never>

// Deserialize from wire format
const deserializeResponse: (
  bytes: Uint8Array,
  req: HttpClientRequest
) => HttpClientResponse

Testing Patterns

Using with Bun Test

import { describe, expect, it } from "bun:test";
import { Effect, Layer } from "effect";
import { BunFileSystem } from "@effect/platform-bun";
import { FetchHttpClient, HttpClient } from "@effect/platform";
import { MockHttpClient } from "mockhttp";

// Helper for Effect-based tests
export function itEffect<A, E>(
  name: string,
  eff: () => Effect<A, E, never>,
  opts?: { timeoutMs?: number }
) {
  return it(name, async () =>
    await (opts?.timeoutMs
      ? eff().pipe(Effect.timeout(opts.timeoutMs))
      : eff()
    ).pipe(
      Effect.catchAllCause((cause) =>
        Effect.sync(() => {
          throw new Error(Cause.pretty(cause));
        })
      ),
      Effect.runPromise
    )
  );
}

describe("API Tests", () => {
  const mockLayer = MockHttpClient.makeWithRecord("./tests/.mock_responses").pipe(
    Layer.provide(BunFileSystem.layer),
    Layer.provide(FetchHttpClient.layer)
  );

  itEffect("should fetch user data", () =>
    Effect.gen(function* () {
      const client = yield* HttpClient.HttpClient;
      const response = yield* client.get("https://api.example.com/user/123");
      const user = yield* response.json;
      expect(user.id).toBe(123);
    }).pipe(Effect.provide(mockLayer))
  );
});

Organizing Mock Files

project/
├── src/
├── tests/
│   ├── .mock_responses/
│   │   ├── R0VUIGF_base64_encoded_request.http
│   │   └── UE9TVCBh_base64_encoded_request.http
│   └── api.test.ts
└── package.json

CI/CD Considerations

  1. Commit mock files: Add .mock_responses to version control
  2. Deterministic tests: Tests always use the same responses
  3. Update mocks: Delete specific files to re-record responses
  4. Clean mocks: rm -rf .mock_responses to re-record all

Advanced Usage

Custom Storage Directory

const customMockLayer = MockHttpClient.make("./test-fixtures/http-mocks").pipe(
  Layer.provide(BunFileSystem.layer)
);

Selective Recording

// Use different layers for different test suites
const integrationMocks = MockHttpClient.makeWithRecord("./mocks/integration");
const unitMocks = MockHttpClient.make("./mocks/unit");

Error Handling

const program = Effect.gen(function* () {
  const client = yield* HttpClient.HttpClient;
  const response = yield* client.get("https://api.example.com/data");
  return yield* response.json;
}).pipe(
  Effect.catchTag("RequestError", (error) =>
    Effect.succeed({ fallback: true })
  )
);

Best Practices

  1. Organize by Feature: Group mock files by feature or API endpoint
  2. Version Control: Commit mock files for reproducible tests
  3. Regular Updates: Periodically refresh mocks to catch API changes
  4. Review Changes: Review mock file diffs to spot API changes
  5. Environment Separation: Use different mock directories for different environments

Troubleshooting

Mock Not Found

If you get a file not found error, the mock doesn't exist yet:

  • Switch to makeWithRecord to capture it
  • Or manually create the mock file

Stale Mocks

If tests pass but production fails:

  • Delete the mock file to force re-recording
  • Compare old vs new mock to see what changed

Debugging

Check the .mock_responses directory to see:

  • What requests are being made
  • What responses are being returned
  • File naming patterns

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT