@x12i/api-simulator
v1.3.0
Published
Transport-agnostic framework for fixed, relative-template, and function-based API simulations.
Maintainers
Readme
@x12i/api-simulator
A transport-agnostic TypeScript library for defining and running simulated APIs. Use it directly in tests, expose it through the included Node.js or Fetch adapters, or integrate it with frameworks such as Express and Fastify.
Features
- Fixed, template-based, and function-based endpoint behavior
- Path parameters, query strings, headers, and request-body matching
- Multiple APIs with independent base paths, hosts, and local data
- Runtime definition and template validation
- CORS, header authentication, bearer-token, and rate-limit helpers
- In-memory CRUD store, per-API mutable
context.state, and OpenAPI skeletons - Request history and raw text or binary responses
- Node.js HTTP, Fetch route-handler, and client
fetchinterceptors - JSON/YAML endpoint packs with a simulation handler registry
- Connector Framework (APS-CF): conformance sessions, deterministic faults, redacted history, signed push, and a versioned scenario catalog for Memorix connector certification
- Zero runtime dependencies (CF push/signing uses Node built-ins only)
Requirements
- Node.js 20 or newer
- TypeScript is optional; declarations are included
Installation
npm install @x12i/api-simulatorDocs knowledge pack (devDependency only — not a substitute for the runtime at certification gates):
npm i -D @x12i/api-simulator-docsQuick start
import { createApiSimulator } from '@x12i/api-simulator';
const simulator = createApiSimulator({
apis: [
{
id: 'users-api',
basePath: '/api',
data: {
users: [{ id: 'user-1', name: 'Ada' }]
},
endpoints: [
{
id: 'health',
method: 'GET',
path: '/health',
behavior: {
type: 'fixed',
response: { status: 200, body: { status: 'ok' } }
}
},
{
id: 'get-user',
method: 'GET',
path: '/users/:userId',
behavior: {
type: 'relative',
response: {
body: {
id: '{{request.params.userId}}',
users: '{{data.users}}'
}
}
}
},
{
id: 'sum',
method: 'POST',
path: '/sum',
behavior: {
type: 'simulation',
handler: ({ request }) => {
const values = (request.body as { values: number[] }).values;
return {
body: { total: values.reduce((sum, value) => sum + value, 0) }
};
}
}
}
]
}
]
});
const match = await simulator.dispatch({
method: 'GET',
path: '/api/users/user-1'
});
// Worker clients can pass the absolute URL they already built:
await simulator.dispatch({
method: 'GET',
url: 'https://api.example/api/users/user-1'
});
console.log(match.response.body);Endpoint behaviors
Every endpoint defines exactly one behavior:
fixedreturns a configured response.relativerenders a response from request values and API-local data.simulationruns a function for validation, branching, state changes, or computed responses.
The library never loads application data from disk, a database, or a remote
service. Pass data in the simulator definition, mutate context.state, or close
over createStore in a simulation handler. Optional @x12i/api-simulator/packs
loads endpoint definitions (not application data) from JSON/YAML.
Package entry points
import { createApiSimulator } from '@x12i/api-simulator';
import { createNodeHttpHandler } from '@x12i/api-simulator/node';
import { createFetchHandler, createSimulatorFetch } from '@x12i/api-simulator/fetch';
import { createStore } from '@x12i/api-simulator/store';
import { createApiSimulatorFromFile } from '@x12i/api-simulator/packs';
import {
rateLimit,
requireBearerToken,
requireHeader
} from '@x12i/api-simulator/helpers';
import { openapiToApiDefinition } from '@x12i/api-simulator/openapi';
import { createConformanceSession, listScenarios } from '@x12i/api-simulator/scenarios';
import { createFaultScheduler, createCursorPager } from '@x12i/api-simulator/cf';
import { signBodyBytes, APS_CF_TEST_SIGNING_KEY } from '@x12i/api-simulator/push';Connector Framework (APS-CF)
For Memorix connector conformance, start a named scenario session (no Mongo/Memorix/Credorix):
import { createConformanceSession } from '@x12i/api-simulator/scenarios';
const session = createConformanceSession({
scenarioId: 'cf.pull.cursor-multipage',
sessionId: 'ci-1',
seed: 42
});
const page = await session.fetch('/v1/items');
session.injectFault({ kind: 'rate_limit', options: { retryAfterSec: 1 } });
const history = session.getHistory(); // secrets redacted
session.reset();
session.stop();See the Connector Framework book for the scenario catalog, push matrix, and Memorix compatibility matrix.
Mutable simulation state
api.data stays read-only for templates. Action endpoints share a per-API bag on
context.state (single-process, not durable). createStore remains available
for typed CRUD collections.
{
id: 'edr',
data: { endpoints: [{ id: 'ep-1', hostname: 'workstation' }] },
endpoints: [
{
id: 'isolate',
method: 'POST',
path: '/isolate',
behavior: {
type: 'simulation',
handler: ({ request, state }) => {
const isolated = state.get('isolated') ?? new Set();
isolated.add(request.body.id);
state.set('isolated', isolated);
return { body: { reply: true } };
}
}
},
{
id: 'list',
method: 'GET',
path: '/endpoints',
behavior: {
type: 'simulation',
handler: ({ data, state }) => {
const isolated = state.get('isolated') ?? new Set();
return {
body: {
items: data.endpoints.map((item) => ({
...item,
isolated: isolated.has(item.id)
}))
}
};
}
}
}
]
}
simulator.resetState(); // between testsClient fetch interceptor
import { createSimulatorFetch } from '@x12i/api-simulator/fetch';
const fetch = createSimulatorFetch(simulator, { unmatched: 'throw' });
await fetch('https://api.xdr.example/public_api/v1/healthcheck');
// Live passthrough when no endpoint matches:
const fetchOrLive = createSimulatorFetch(simulator, {
unmatched: 'passthrough'
});Inject the returned function as fetch (including undici's fetch option). Auth
and signing stay in the vendor client.
Publish the runtime:
npm run publish:runtimeExamples and tools
- Playground — quickly define and dispatch requests
- Studio — local-first simulator authoring
- REST tutorial
- FlowState integration tutorial
Documentation
Read the complete guides, behavior reference, adapter documentation, and use cases at docs.api-simulator.x12i.com.
Development
npm install
npm run validateAdditional commands:
npm run dev:playground
npm run dev:studio
npm run docsLocal services use the api-simulator port zone (5520–5539).
License
MIT
