# Expose a Node.js HTTP service

> **Use case id:** `expose-node-service`
> **Goal:** Wrap a simulator with the Node HTTP adapter, and for processes that bind a port use @x12i/core-service (/health, /_live).
> **Audiences:** developers
> **Tags:** node, http, adapters, core-service

## Reading path

1. **Adapters and Helpers** (developers) → chapters: `1-node-http-adapter`, `2-http-process-compliance-local-services`, `3-multiple-apis`, `7-express-and-fastify`

## From: Adapters and Helpers — 1. Node HTTP adapter

```ts
import { createServer } from 'node:http';
import { createNodeHttpHandler } from '@x12i/api-simulator/node';

createServer(createNodeHttpHandler(simulator)).listen(5520);
```

The adapter:

- parses URL path and query values;
- normalizes request headers to lowercase keys (values may be `string | string[]`);
- parses JSON, urlencoded, and text bodies by default; returns `Buffer` for binary;
- returns `404` when no simulated endpoint matches;
- returns `500` when rendering or simulation fails;
- limits request bodies to 1 MiB by default;
- writes `RawResponseBody` verbatim (HTML/XML/CSV/binary).

The `./node` adapter is **transport-only**. It does not bind ports, serve `/_live`, or print a compliance banner. Processes that **listen on HTTP** should wrap it with `@x12i/core-service` (next section).

---

## From: Adapters and Helpers — 2. HTTP process compliance (local services)

Any example or package simulator that **binds an HTTP port** should use [`@x12i/core-service`](https://www.npmjs.com/package/@x12i/core-service) (pulls `@x12i/api-live-view`; uses `@x12i/ports-manager`).

Product contract (current **`@x12i/memorix-docs`**, not old memorix-ebooks):

- Use case **`http-process-compliance`**
- Building Services (developers) → **HTTP process compliance (local services)**
- Deep reference: package READMEs for `core-service`, `ports-manager`, `api-live-view`

This repo applies that contract in zone **`api-simulator` (5520–5539)** — not Memorix’s 5100–5119.

| Surface | Role |
|--------|------|
| Port from zone map | `scripts/api-simulator-ports.mjs` / `createSimulatorHttp` |
| `GET /health` | Process liveness |
| `/_live` | In-process request rings (api-live-view) |
| `x-correlation-id` | Request/response correlation |
| Startup banner | origin · health · live · docs |

Shared helper:

```js
import { createSimulatorHttp } from '../../scripts/create-simulator-http.mjs';

const { core, announce } = createSimulatorHttp({
  id: 'my-simulator',
  title: 'My package simulator',
  portKey: 'api', // or flowstate / libraryDemo
  portEnv: 'API_SIMULATOR_API_PORT'
});

const server = createServer(async (req, res) => {
  if (await core.tryHandleCore(req, res)) return;
  await createNodeHttpHandler(simulator)(req, res);
});

await announce(server);
```

Published `@x12i/api-simulator` stays **zero runtime dependencies**. Remote *clients* do not install these kits; *servers that bind* do.

---

## From: Adapters and Helpers — 3. Multiple APIs

A single simulator can expose many APIs. Each API has its own `id`, optional `basePath`, internal `data`, and endpoints.

```ts
const simulator = createApiSimulator({
  apis: [crmApi, billingApi, identityApi]
});
```

Duplicate `METHOD + full path` routes are rejected during startup. Structurally ambiguous routes such as `/users/:id` and `/users/:name` are also rejected. Static routes are matched before parameter routes.

---

## From: Adapters and Helpers — 7. Express and Fastify

```ts
// Express
app.use(async (req, res) => {
  const match = await simulator.tryDispatch({
    method: req.method,
    path: req.path,
    headers: req.headers,
    query: req.query,
    body: req.body
  });
  if (!match) return res.status(404).json({ error: 'NOT_FOUND' });
  res.status(match.response.status ?? 200).set(match.response.headers ?? {}).send(match.response.body);
});
```

---

## Also see

- **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._
