# Structured Output / JSON Mode

aimock supports matching on `response_format` so you can return different responses for JSON mode requests versus regular text requests. Use `match.responseFormat` in fixtures or the `onJsonOutput()` convenience method.

## How It Works

- When a request includes `response_format: { type: "json_object" }`, the router checks `match.responseFormat`
- Fixtures with `responseFormat: "json_object"` only match JSON mode requests
- Regular fixtures (without responseFormat) still match JSON mode requests if no specific JSON fixture matches first

## Unit Test: Programmatic API

json-output.test.ts ts

    const mock = new LLMock();
    await mock.start();

    // Register JSON output fixture — accepts object or string
    mock.onJsonOutput("json-output", { answer: 42, items: ["a", "b"] });

    const res = await fetch(`${mock.url}/v1/chat/completions`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        model: "gpt-4",
        messages: [{ role: "user", content: "json-output" }],
        stream: false,
        response_format: { type: "json_object" },
      }),
    });

    const body = await res.json();
    const content = JSON.parse(body.choices[0].message.content);
    expect(content.answer).toBe(42);
    expect(content.items).toEqual(["a", "b"]);

## JSON Fixture

fixtures/json-mode.json json

    {
      "fixtures": [
        {
          "match": {
            "userMessage": "json-output",
            "responseFormat": "json_object"
          },
          "response": {
            "content": { "answer": 42, "items": ["a", "b"] }
          }
        }
      ]
    }

Auto-stringify: The `content` field accepts objects in fixture files. The loader detects `typeof === "object"` and calls `JSON.stringify()` automatically. The escaped-string form (`"{\"answer\":42}"`) still works for backward compatibility.

## Match Behavior

Each row shows whether a request matches a fixture based on the combination of their `responseFormat` values. A fixture without `responseFormat` is a wildcard (matches all requests), but a fixture with `responseFormat` is a filter (only matches requests that specify that format).

Request response_format | Fixture responseFormat | Match?
--- | --- | ---
{ type: "json_object" } | "json_object" | Yes
{ type: "json_object" } | (not set) | Yes (fallthrough)
(not set) | "json_object" | No
(not set) | (not set) | Yes

The `onJsonOutput()` method accepts either a plain object (auto-serialized) or a string. This makes it easy to return structured data without manual `JSON.stringify`.