Skip to content

Recover & Transform

recover and transform are the two hooks that change the return value. They’re separate from observability hooks (onError/onSuccess), which are side-effect-only.

A true catch-all that wraps the entire error path. If it returns a non-undefined value, that value becomes the result instead of throwing.

const config = await expectStatus(200, api.getFeatureFlags(), {
recover: () => DEFAULT_FLAGS,
})
// config is FeatureFlags — never throws
  • Feature flags / config — fall back to defaults on any error
  • Cached data — serve stale data when the API is down
  • Optional data — return null instead of throwing
// Serve stale cache on failure
const data = await expectStatus(200, api.getDashboard(), {
recover: () => cache.get('dashboard'),
})
// Optional: return null
const profile = await expectStatus(200, api.getProfile(id), {
recover: () => null,
})

If recover returns undefined, the original error is re-thrown:

await expectStatus(200, response, {
recover: (err) => {
if (err.message.includes('rate limit')) return FALLBACK
return undefined // re-throws the original error
},
})

onError fires before recover. Both receive the same error.

Reshapes the success body before returning:

const wrapped = await expectStatus(200, response, {
transform: (body) => ({ data: body, fetchedAt: Date.now() }),
})
  • Wrapping — add metadata to the response body
  • Normalizing — reshape to match your app’s internal types
  • Selecting — pluck a nested field
// Pluck a nested field
const users = await expectStatus(200, api.listUsers(), {
transform: (body) => body.data.users,
})

Both hooks can be set in defaults — per-call overrides shadow them:

const expectStatus = createExpectStatus({
defaults: {
transform: (body) => ({ data: body }),
recover: (err) => ({ error: err.message }),
},
})
// Per-call override
await expectStatus(200, response, {
transform: (body) => body.items, // shadows default transform
})

When transform or recover is provided, the return type widens to Promise<unknown> because the hooks can return anything.