Integrations & Testing
HTTP Adapter (custom fetch / edge environments)
Replace the built-in axios client with any HTTP implementation:
js
const fetchAdapter = {
async request(config) {
const url = `${config.baseURL ?? ''}${config.url ?? ''}`
const res = await fetch(url, {
method: config.method ?? 'GET',
body: config.data ? JSON.stringify(config.data) : undefined,
headers: { 'Content-Type': 'application/json', ...config.headers },
signal: config.signal,
})
const data = await res.json()
return {
data,
status: res.status,
statusText: res.statusText,
headers: Object.fromEntries(res.headers.entries()),
}
},
}
const client = createRestClient({
baseURL: 'https://api.example.com',
adapter: fetchAdapter,
// Auth, interceptors, sanitizeHeaders, metrics still work on top of the adapter
auth: { getToken: async () => token },
})ts
type HttpAdapter = {
request<T = unknown>(config: RestRequestConfig & { baseURL?: string }): Promise<ApiResponse<T>>
}When adapter is set, createRestClient() never calls axios.create() — the built-in axios instance simply isn't constructed, so adapter-only usage (e.g. in Cloudflare Workers / Deno) doesn't pay for it.
Vue integration
vue
<script setup>
import {
PipelineOrchestrator,
usePipelineProgressVue,
usePipelineRunVue,
} from 'rest-pipeline-js/vue'
const orchestrator = new PipelineOrchestrator({
config: {
stages: [/* ... */],
},
})
const progress = usePipelineProgressVue(orchestrator)
const { run, running, result, error, abort, pause, resume, rerunStep } =
usePipelineRunVue(orchestrator)
</script>
<template>
<div>
<div>Current stage: {{ progress.currentStage }}</div>
<button @click="run()" :disabled="running">Start</button>
<button @click="abort()" :disabled="!running">Abort</button>
<button @click="pause()">Pause</button>
<button @click="resume()">Resume</button>
<div v-if="result">Done: {{ result }}</div>
<div v-if="error">Error: {{ error.message }}</div>
</div>
</template>Composables (import from rest-pipeline-js/vue):
| Composable | Returns | Description |
|---|---|---|
usePipelineProgressVue(orchestrator) | Ref<PipelineProgress> | Reactive progress |
usePipelineRunVue(orchestrator) | { run, running, result, error, stageResults, abort, pause, resume, rerunStep, clearStageResults } | Run pipeline and get reactive state |
usePipelineStepEventVue(orchestrator, stepKey, eventType) | Ref<any> | Last payload for a specific step event |
usePipelineLogsVue(orchestrator) | Ref<log[]> | Reactive logs |
useRerunPipelineStepVue(orchestrator) | function | Bound rerunStep |
useRestClientVue(config) | ComputedRef<RestClient> | Reactive REST client |
usePipelineStageResultVue(orchestrator, stepKey) | Ref<PipelineStepResult | null> | Reactive result of a single stage |
React integration
jsx
import { useRef } from 'react'
import {
PipelineOrchestrator,
usePipelineProgressReact,
usePipelineRunReact,
} from 'rest-pipeline-js/react'
const orchestrator = new PipelineOrchestrator({
config: {
stages: [/* ... */],
},
})
export function PipelineComponent() {
const progress = usePipelineProgressReact(orchestrator)
const [run, { running, result, error, abort, pause, resume, rerunStep, clearStageResults }] =
usePipelineRunReact(orchestrator)
return (
<div>
<div>Current stage: {progress.currentStage}</div>
<button onClick={() => run()} disabled={running}>
Start
</button>
<button onClick={() => abort()} disabled={!running}>
Abort
</button>
<button onClick={() => pause()}>Pause</button>
<button onClick={() => resume()}>Resume</button>
{result && <div>Done: {JSON.stringify(result)}</div>}
{error && <div>Error: {error.message}</div>}
</div>
)
}Hooks (import from rest-pipeline-js/react):
| Hook | Returns | Description |
|---|---|---|
usePipelineProgressReact(orchestrator) | PipelineProgress | Reactive progress |
usePipelineRunReact(orchestrator) | [run, { running, result, error, stageResults, abort, pause, resume, rerunStep, clearStageResults }] | Run pipeline and get state |
usePipelineStepEventReact(orchestrator, stepKey, eventType) | any | Last payload for a specific step event |
usePipelineLogsReact(orchestrator) | log[] | Reactive logs |
useRerunPipelineStepReact(orchestrator) | function | Bound rerunStep |
useRestClientReact(config) | RestClient | Memoized REST client — recreated when config is a new object reference; memoize it yourself (useMemo/useState/module-level constant) to avoid recreating it every render |
usePipelineStageResultReact(orchestrator, stepKey) | PipelineStepResult | null | Result of a single stage |
Testing
createMockAdapter() (from the separate rest-pipeline-js/testing entry point, so it never ships in a production bundle) replaces the network with a set of route definitions — for testing code that uses createRestClient() or PipelineOrchestrator without hitting a real backend:
ts
import { createRestClient } from 'rest-pipeline-js'
import { createMockAdapter } from 'rest-pipeline-js/testing'
const adapter = createMockAdapter([
{ method: 'GET', url: '/users/1', respond: { data: { id: 1, name: 'Ada' } } },
// Dynamic response — reads the request to build the reply
{
method: 'POST',
url: '/orders',
respond: (info) => ({ data: { id: 42, ...(info.data as object) }, status: 201 }),
},
// Sequence of responses, one per matching call — exercise retry logic:
// first two attempts fail, third succeeds. Repeats the last entry once exhausted.
{
method: 'GET',
url: '/flaky',
respond: [{ error: true, status: 503 }, { error: true, status: 503 }, { data: { ok: true } }],
},
])
const client = createRestClient({ baseURL: 'https://api.example.com', adapter })
const user = await client.get('/users/1')
// adapter.calls — history of every request handled, in order; assert on it in your tests
expect(adapter.calls).toHaveLength(1)urlmatches by substring (string) or.test()(RegExp) against the relative URL (config.url, e.g./users/1), not the full URL. Omitmethodto match any method.- A response with
status >= 400rejects by default (matching what axios/fetch do), thrown asErrorwith.statusand.response.status/.response.data/.response.headersset — enough forretry.retriableStatus,circuitBreaker, and error interceptors to work against. Override with an expliciterror: true/falseon the response spec. delayMson a response simulates network latency with a realsetTimeout(works fine undervi.useFakeTimers()/similar).- No route matching a request throws immediately with a clear message, instead of hanging — a test with a missing route setup fails loudly.
adapter.reset()clearscallsand rewinds any array-respondsequences back to their start, without touching the routes themselves.
See examples/mock-adapter.ts for a fuller example, including use with PipelineOrchestrator via httpConfig.