Dream Mock Server

A general-purpose HTTP mock server developed by Dream that provides both streaming and non-streaming endpoints for testing HTTP clients.

Current module version: 1.1.0

Overview

This module provides a comprehensive set of endpoints for testing HTTP clients:

All endpoints are deterministic and designed for testing, making them ideal for:

Running

Standalone Mode

Start the server on port 3004:

make run

Then access endpoints at http://localhost:3004/

Programmatic Mode

Use in tests or other applications:

import dream_mock_server/server

pub fn my_test() {
  let assert Ok(handle) = server.start(3004)
  
  // Make HTTP requests to localhost:3004
  // ... test logic ...
  
  server.stop(handle)
}

πŸ§ͺ Tested source

Config mode

For proxy tests or any test that needs a deterministic upstream with specific status and body per path, start the server with a config list. The mock has no built-in provider logic (no OpenAI, Google, AWS, etc.); the caller supplies all path β†’ (status, body) mappings. First matching route in the list wins.

import dream_mock_server/config.{MockRoute, Prefix}
import dream_mock_server/server
import gleam/option.{None}

// One route: path /v1/chat/completions (prefix match), any method, 200 + JSON body
let config = [
  MockRoute(
    path: "/v1/chat/completions",
    path_match: Prefix,
    method: None,
    status: 200,
    body: "{\"choices\":[{\"message\":{\"content\":\"\"}}]}",
  ),
]
let assert Ok(handle) = server.start_with_config(3004, config)
// Point your proxy or client at http://127.0.0.1:3004 ...
server.stop(handle)

πŸ§ͺ Tested source

How matching works

Exact + method-specific example

import dream/http/request.{Get, Post}
import dream_mock_server/config.{Exact, MockRoute}
import dream_mock_server/server
import gleam/option.{Some}

let config = [
  MockRoute("/resource", Exact, Some(Get), 200, "{\"ok\":true}"),
  MockRoute("/resource", Exact, Some(Post), 201, "{\"created\":true}"),
]
let assert Ok(handle) = server.start_with_config(3004, config)
// GET /resource  -> 200 {"ok":true}
// POST /resource -> 201 {"created":true}
server.stop(handle)

πŸ§ͺ Tested source

Ordering gotcha (important)

If you mix broad prefixes and specific routes, put specific routes first:

// Good: specific before broad prefix
[
  MockRoute("/api/special", Exact, None, 200, "special"),
  MockRoute("/api", Prefix, None, 200, "general"),
]

πŸ§ͺ Tested source

Non-Streaming Endpoints

GET /get

Returns JSON with request info

Use for: Testing GET requests, JSON parsing

POST /post

Echoes request body as JSON

Use for: Testing POST requests, request body handling

PUT /put

Echoes request body as JSON

Use for: Testing PUT requests

DELETE /delete

Returns success response

Use for: Testing DELETE requests

GET /json

Returns simple JSON object

Use for: Testing JSON parsing, simple responses

GET /text

Returns plain text

Use for: Testing text responses

GET /uuid

Returns UUID-like string

Use for: Testing small JSON responses

GET /

Info page - Lists all available endpoints with descriptions

Use for: Documentation, service discovery

Streaming Endpoints

GET /stream/fast

10 chunks at 100ms intervals

Use for: Testing fast streaming, basic functionality

GET /stream/slow

5 chunks at 2s intervals

Use for: Testing timeout handling, long-running streams

GET /stream/burst

7 chunks with variable delays (100-500ms)

Use for: Testing variable timing patterns, buffering behavior

GET /stream/error

3 chunks then 500 status

Use for: Testing error handling mid-stream

GET /stream/huge

100 chunks with 10ms delays

Use for: Memory efficiency, performance testing

GET /stream/json

5 JSON objects at 200ms intervals

Use for: Testing structured data streaming, JSON handling

GET /stream/binary

256 binary chunks with byte patterns

Use for: Testing binary data streaming

Integration Tests

Run Cucumber integration tests:

make test-integration

Tests verify:

Usage Modes

1. Standalone Server

Fixed port 3004, runs indefinitely:

make run

2. Programmatic Control

Start/stop programmatically for tests:

import dream_mock_server/server

// Start server
let assert Ok(handle) = server.start(3004)

// Use server...

// Stop server
server.stop(handle)

3. Integration Testing

Used by Dream’s HTTP client tests:

// In modules/http_client/test/integration_test.gleam
import dream_mock_server/server

pub fn concurrent_streams_test() {
  let assert Ok(mock) = server.start(3004)
  
  // Test HTTP client against localhost:3004
  // ...
  
  server.stop(mock)
}

Implementation Details

Streaming Technique

Streaming endpoints use Dream’s response.stream_response():

import dream/http/response.{stream_response}
import dream/http/status
import gleam/yielder
import gleam/erlang/process

pub fn stream_fast(...) -> Response {
  let stream =
    yielder.range(1, 10)
    |> yielder.map(fn(n) {
      process.sleep(100)
      let line = "Chunk " <> int.to_string(n) <> "\n"
      bit_array.from_string(line)
    })

  stream_response(status.ok, stream, "text/plain")
}

Non-Streaming Technique

Non-streaming endpoints use standard json_response() and text_response():

import dream/http/response.{json_response}
import dream/http/status
import gleam/json

pub fn get(...) -> Response {
  let body =
    json.object([
      #("method", json.string("GET")),
      #("url", json.string(request.path)),
    ])
    |> json.to_string
  
  json_response(status.ok, body)
}

Timing Control

Streaming endpoints use process.sleep() between chunks for deterministic timing:

Error Simulation

The /stream/error endpoint demonstrates mid-stream errors by returning a 500 status with partial content. This tests client error handling during streaming.

Architecture

src/
β”œβ”€β”€ main.gleam                    # Standalone entry point (port 3004)
β”œβ”€β”€ dream_mock_server/
β”‚   β”œβ”€β”€ server.gleam             # Programmatic start/stop functions
β”‚   β”œβ”€β”€ router.gleam             # Route definitions
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   β”œβ”€β”€ api_controller.gleam      # Non-streaming endpoints
β”‚   β”‚   └── stream_controller.gleam   # Streaming endpoints
β”‚   └── views/
β”‚       └── index_view.gleam          # Info page HTML

Dependencies

All Examples Are Tested

The core usage examples in this README are backed by runnable snippet tests under test/snippets/ and executed by test/snippets_test.gleam.

Run them with:

cd modules/mock_server
gleam test

See Also

✨ Search Document