# Define the three endpoint behaviors

> **Use case id:** `define-three-behaviors`
> **Goal:** Author fixed, relative, and simulation endpoints and dispatch them from tests or adapters.
> **Audiences:** developers
> **Tags:** behaviors, dispatch

## Reading path

1. **Behaviors and Dispatch** (developers) → chapters: `1-fixed`, `2-relative`, `3-simulation-function`, `4-dispatch`, `5-endpoint-contract`

## From: Behaviors and Dispatch — 1. Fixed

Use fixed behavior for health endpoints, stable metadata, constants, and simple fixtures.

```ts
{
  id: 'capabilities',
  method: 'GET',
  path: '/capabilities',
  behavior: {
    type: 'fixed',
    response: {
      status: 200,
      headers: { 'x-simulator': 'true' },
      body: { features: ['read', 'search'] }
    }
  }
}
```

---

## From: Behaviors and Dispatch — 2. Relative

Relative behavior starts with configured JSON, then resolves tokens against the matched request and the API's internal `data` object.

Supported token roots:

- `{{request.params.parentId}}`
- `{{request.query.page}}`
- `{{request.headers.x-tenant-id}}`
- `{{request.body.customer.id}}`
- `{{data.children}}`
- Array indexes, such as `{{data.users[0].id}}`

```ts
{
  id: 'children',
  method: 'GET',
  path: '/parents/:parentId/children',
  behavior: {
    type: 'relative',
    response: {
      body: {
        parentId: '{{request.params.parentId}}',
        items: '{{data.children}}'
      }
    }
  }
}
```

A token occupying the entire string preserves its original type. Therefore, `{{request.body.limit}}` can produce a number and `{{data.children}}` can produce an array. A token embedded inside text is converted to a string:

```ts
{ message: 'Children for parent {{request.params.parentId}}' }
```

Tokens inside API-local data are rendered too. This lets a reusable internal fixture inherit an identifier from the incoming request:

```ts
data: {
  children: [
    { id: 'child-1', parentId: '{{request.params.parentId}}' }
  ]
}
```

Relative behavior is strict by default. A missing token throws `TemplateResolutionError`. Set `strict: false` to leave unresolved tokens unchanged.

---

## From: Behaviors and Dispatch — 3. Simulation function

Use a simulation function when output needs conditions, calculations, validation, generated values, branching, or error responses.

```ts
{
  id: 'quote',
  method: 'POST',
  path: '/quote',
  behavior: {
    type: 'simulation',
    handler: async ({ request, data, apiId, endpointId }) => {
      const quantity = Number((request.body as { quantity: number }).quantity);
      const unitPrice = Number(data.unitPrice);

      return {
        status: 201,
        body: {
          apiId,
          endpointId,
          quantity,
          unitPrice,
          total: quantity * unitPrice
        }
      };
    }
  }
}
```

---

## From: Behaviors and Dispatch — 4. Dispatch

```ts
const result = await simulator.dispatch({
  method: 'GET',
  path: '/api/v1/parents/parent-42/children'
});

console.log(result.response.body);
```

`dispatch()` throws `EndpointNotFoundError` when nothing matches. `tryDispatch()` returns `undefined` instead.

---

## From: Behaviors and Dispatch — 5. Endpoint contract

```ts
type EndpointDefinition = {
  id: string;
  method: HttpMethod;
  path: string;
  enabled?: boolean;
  delayMs?: number;
  behavior:
    | { type: 'fixed'; response: SimulatorResponse }
    | { type: 'relative'; response: SimulatorResponse; strict?: boolean }
    | { type: 'simulation'; handler: SimulationFunction };
};
```

The discriminated `behavior` union is the core guarantee: an endpoint cannot validly have two behaviors, and it cannot omit its behavior.

---

## Also see

- **Behaviors and Dispatch** (`01-behaviors`) — The three endpoint behaviors, dispatch APIs, contracts, latency, raw bodies, and path patterns.
- **Adapters and Helpers** (`02-adapters`) — Expose simulators over HTTP, compose helpers, and plug into Express, Fastify, or fetch runtimes.

---

_Generated use-case pack for agents and humans. See `agent-manifest.json` for discovery._
