From bb94a52bd1e0b8700b5120b7d6f3317aef582008 Mon Sep 17 00:00:00 2001 From: Roman Onishchenko Date: Sun, 15 Mar 2026 12:51:04 +0100 Subject: [PATCH 1/5] add retry support --- docs/v1/retry.md | 179 ++++++++++++++++++++++++++++++++++ src/content/docsContent.ts | 1 + src/content/docsNavigation.ts | 1 + 3 files changed, 181 insertions(+) diff --git a/docs/v1/retry.md b/docs/v1/retry.md index e69de29..fd8b6ff 100644 --- a/docs/v1/retry.md +++ b/docs/v1/retry.md @@ -0,0 +1,179 @@ +# Retry + +`@dfsync/client` supports configurable retry policies for transient failures. + +Retries are useful when communicating with external services that may temporarily fail or return `5xx` responses. + +The retry behavior can be configured globally for the client or overridden per request. + +--- + +## Basic retry configuration + +```ts +import { createClient } from '@dfsync/client'; + +const client = createClient({ + baseUrl: 'https://api.example.com', + retry: { + attempts: 2, + }, +}); +``` + +If a retryable error occurs, the request will be retried up to the configured number of attempts. + +## Retry conditions + +By default, retries happen for: + +- network errors +- HTTP 5xx responses + +Example: + +```ts +const client = createClient({ + baseUrl: 'https://api.example.com', + retry: { + attempts: 3, + }, +}); +``` + +## Retry backoff + +Two retry strategies are supported: + +### Fixed delay + +```ts +const client = createClient({ + baseUrl: 'https://api.example.com', + retry: { + attempts: 3, + backoff: 'fixed', + baseDelayMs: 300, + }, +}); +``` + +Retry delays: + +```bash +300ms +300ms +300ms +``` + +### Exponential backoff + +```ts +const client = createClient({ + baseUrl: 'https://api.example.com', + retry: { + attempts: 3, + backoff: 'exponential', + baseDelayMs: 300, + }, +}); +``` + +Retry delays: + +```bash +300ms +600ms +1200ms +``` + +If `attempts` is `0` (default), no retries are performed and retry delays are ignored. + +## Retry methods + +By default retries apply to: + +- `GET` +- `PUT` +- `DELETE` + +POST requests are **not retried by default**. + +Example enabling POST retries: + +```ts +const client = createClient({ + baseUrl: 'https://api.example.com', + retry: { + attempts: 2, + retryMethods: ['GET', 'POST'], + }, +}); +``` + +## Retry conditions configuration + +You can control which errors trigger retries. + +Supported conditions: + +- network-error +- 5xx +- 429 + +Example: + +```ts +const client = createClient({ + baseUrl: 'https://api.example.com', + retry: { + attempts: 2, + retryOn: ['network-error', '5xx', '429'], + }, +}); +``` + +## Per-request retry override + +Request-level configuration overrides the client configuration. + +```ts +await client.get('/users', { + retry: { + attempts: 1, + }, +}); +``` + +## Retry and hooks + +Hooks behave as follows when retries are enabled: + +| Hook | Behavior | +| --------------- | ------------------------------------- | +| `beforeRequest` | executed on every retry attempt | +| `afterResponse` | executed only on successful response | +| `onError` | executed once after the final failure | + +Example: + +```ts +const client = createClient({ + baseUrl: 'https://api.example.com', + retry: { attempts: 2 }, + hooks: { + onError(ctx) { + console.error(ctx.error); + }, + }, +}); +``` + +## Summary + +Retry is designed for **safe and predictable service-to-service communication** and works well for: + +- microservices +- external APIs +- background workers +- integration services diff --git a/src/content/docsContent.ts b/src/content/docsContent.ts index 9b5af15..94c667d 100644 --- a/src/content/docsContent.ts +++ b/src/content/docsContent.ts @@ -5,6 +5,7 @@ export const docsContent = { 'create-client': () => import('../../docs/v1/create-client.md?raw'), auth: () => import('../../docs/v1/auth.md?raw'), hooks: () => import('../../docs/v1/hooks.md?raw'), + retry: () => import('../../docs/v1/retry.md?raw'), errors: () => import('../../docs/v1/errors.md?raw'), examples: () => import('../../docs/v1/examples.md?raw'), }, diff --git a/src/content/docsNavigation.ts b/src/content/docsNavigation.ts index 9e4c608..594033d 100644 --- a/src/content/docsNavigation.ts +++ b/src/content/docsNavigation.ts @@ -4,6 +4,7 @@ export const docsNavigation = [ { label: 'Create Client', slug: 'create-client' }, { label: 'Auth', slug: 'auth' }, { label: 'Hooks', slug: 'hooks' }, + { label: 'Retry', slug: 'retry' }, { label: 'Errors', slug: 'errors' }, { label: 'Examples', slug: 'examples' }, ] as const; From fba82f55e6c4c47c28bbc52637ae167fc3ac5779 Mon Sep 17 00:00:00 2001 From: Roman Onishchenko Date: Sun, 15 Mar 2026 12:59:54 +0100 Subject: [PATCH 2/5] update md --- docs/v1/retry.md | 2 +- src/pages/Docs/DocsPage.tsx | 52 ++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/docs/v1/retry.md b/docs/v1/retry.md index fd8b6ff..1d2f3aa 100644 --- a/docs/v1/retry.md +++ b/docs/v1/retry.md @@ -1,6 +1,6 @@ # Retry -`@dfsync/client` supports configurable retry policies for transient failures. +`@dfsync/client` supports `configurable retry` policies for transient failures. Retries are useful when communicating with external services that may temporarily fail or return `5xx` responses. diff --git a/src/pages/Docs/DocsPage.tsx b/src/pages/Docs/DocsPage.tsx index 59750ba..8c1f59d 100644 --- a/src/pages/Docs/DocsPage.tsx +++ b/src/pages/Docs/DocsPage.tsx @@ -142,13 +142,63 @@ export function DocsPage() { '& pre': { overflowX: 'auto', p: 2, - borderRadius: 0.5, + borderRadius: 1, bgcolor: 'background.default', border: '1px solid', borderColor: 'divider', + mb: 3, }, + + '& pre code': { + fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', + fontSize: 14, + lineHeight: 1.7, + backgroundColor: 'transparent', + padding: 0, + borderRadius: 0, + border: 'none', + }, + '& code': { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', + fontSize: '0.9em', + px: 0.75, + py: 0.25, + borderRadius: 0.5, + bgcolor: 'background.default', + border: '1px solid', + borderColor: 'divider', + }, + '& table': { + width: '100%', + borderCollapse: 'collapse', + mb: 3, + overflow: 'hidden', + borderRadius: 2, + border: '1px solid', + borderColor: 'divider', + }, + '& thead': { + bgcolor: 'background.default', + }, + '& th': { + textAlign: 'left', + px: 2, + py: 1.5, + borderBottom: '1px solid', + borderColor: 'divider', + fontWeight: 700, + }, + '& td': { + px: 2, + py: 1.5, + borderBottom: '1px solid', + borderColor: 'divider', + color: 'text.secondary', + verticalAlign: 'top', + }, + '& tr:last-of-type td': { + borderBottom: 'none', }, '& a': { color: 'primary.main', From 4e73928a627e07e9a7232f667850b2351be5cc15 Mon Sep 17 00:00:00 2001 From: Roman Onishchenko Date: Sun, 15 Mar 2026 13:22:16 +0100 Subject: [PATCH 3/5] update docs --- docs/v1/getting-started.md | 1 + docs/v1/retry.md | 2 +- index.html | 2 +- src/components/Features/Features.tsx | 23 +++++++++++++++++------ src/components/Hero/Hero.tsx | 12 ++++++++---- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/docs/v1/getting-started.md b/docs/v1/getting-started.md index 6a8d3e6..a37c4e6 100644 --- a/docs/v1/getting-started.md +++ b/docs/v1/getting-started.md @@ -21,6 +21,7 @@ The client focuses on predictable behavior, extensibility, and a clean developer - structured error classes - auth support - lifecycle hooks +- retry support - custom `fetch` support ## Quick example diff --git a/docs/v1/retry.md b/docs/v1/retry.md index 1d2f3aa..fd8b6ff 100644 --- a/docs/v1/retry.md +++ b/docs/v1/retry.md @@ -1,6 +1,6 @@ # Retry -`@dfsync/client` supports `configurable retry` policies for transient failures. +`@dfsync/client` supports configurable retry policies for transient failures. Retries are useful when communicating with external services that may temporarily fail or return `5xx` responses. diff --git a/index.html b/index.html index 0acd386..1276cab 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - dfsync — Reliable HTTP client for Node.js Microservices + dfsync — Reliable HTTP communication for Node.js environments. , - title: 'Auth & lifecycle hooks', - description: - 'Built-in support for bearer tokens, API keys, and request lifecycle hooks like beforeRequest, afterResponse, and onError.', + icon: , + title: 'Auth support', + description: 'Built-in support for bearer tokens, API keys.', + }, + { + icon: , + title: 'Retry support', + description: 'Supports configurable retry policies for transient failures.', + }, + { + icon: , + title: 'Lifecycle hooks', + description: 'Built-in request lifecycle hooks like beforeRequest, afterResponse, and onError.', }, { icon: , @@ -40,7 +51,7 @@ export const Features = () => { A focused foundation for dependable HTTP communication between services — with sensible - defaults, auth strategies, and lifecycle hooks. + defaults, auth strategies, lifecycle hooks and retry support. diff --git a/src/components/Hero/Hero.tsx b/src/components/Hero/Hero.tsx index 00fa94e..a4220fc 100644 --- a/src/components/Hero/Hero.tsx +++ b/src/components/Hero/Hero.tsx @@ -27,11 +27,11 @@ export const Hero = () => { maxWidth: 900, }} > - Reliable HTTP communication for modern services. + Reliable HTTP communication for Node.js environments. { lineHeight: 1.6, }} > - dfsync provides a unified HTTP client with sensible defaults for service-to-service - communication across microservices, internal APIs, workers, and external integrations. + dfsync - a lightweight & reliable HTTP client for service-to-service communication + across services in Node.js with retry, auth and lifecycle hooks. @@ -113,6 +113,10 @@ export const Hero = () => { const client = createClient({ baseURL: "https://api.example.com", + retry: { + attempts: 3, + backoff: 'exponential' + }, }); const users = await client.get("/users");`} From 181d7796e73cfe6f62d0ad3303febd4b6feacfeb Mon Sep 17 00:00:00 2001 From: Roman Onishchenko Date: Mon, 16 Mar 2026 09:49:32 +0100 Subject: [PATCH 4/5] update home page --- docs/v1/getting-started.md | 50 ++++++++++++++++++++++------ src/components/Features/Features.tsx | 10 +++--- src/components/Footer/Footer.tsx | 2 +- src/components/Header/Header.tsx | 2 +- src/components/Hero/Hero.tsx | 24 +++++-------- 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/docs/v1/getting-started.md b/docs/v1/getting-started.md index a37c4e6..825a19f 100644 --- a/docs/v1/getting-started.md +++ b/docs/v1/getting-started.md @@ -47,16 +47,46 @@ console.log(user.name); ## How requests work -A request in `@dfsync/client` follows this flow: - -1. build final URL from `baseUrl`, `path`, and optional query params -2. merge default, client-level, and request-level headers -3. apply auth configuration -4. run `beforeRequest` hooks -5. send request with `fetch` -6. parse response as JSON, text, or `undefined` for `204` -7. throw structured errors for failed requests -8. run `afterResponse` or `onError` hooks +A request in `@dfsync/client` goes through the following lifecycle: + +1. Build request URL + + The final URL is constructed from `baseUrl`, `path`, and optional query parameters. + +2. Merge headers + + Default headers, client-level headers, and request-level headers are combined. + +3. Apply authentication + + The configured auth strategy (Bearer, API key, or custom) is applied to the request. + +4. Run `beforeRequest` hooks + + Hooks can modify the request before it is sent. + +5. Execute the HTTP request + + The request is sent using the Fetch API. + +6. Retry if necessary + + If the request fails with a retryable error, it may be retried according to the configured retry policy. + +7. Parse the response + + The response body is parsed automatically: + - JSON → parsed object + - text → string + - `204 No Content` → `undefined` + +8. Handle errors + + Non-success responses and network failures are converted into structured errors. + +9. Run response hooks + - `afterResponse` runs for successful responses + - `onError` runs when an error occurs ## Runtime requirements diff --git a/src/components/Features/Features.tsx b/src/components/Features/Features.tsx index f485737..e3ab126 100644 --- a/src/components/Features/Features.tsx +++ b/src/components/Features/Features.tsx @@ -22,12 +22,12 @@ const items = [ { icon: , title: 'Auth support', - description: 'Built-in support for bearer tokens, API keys.', + description: 'Built-in support for bearer tokens, API keys, and custom auth flows.', }, { icon: , title: 'Retry support', - description: 'Supports configurable retry policies for transient failures.', + description: 'Built-in configurable retry policies for transient failures.', }, { icon: , @@ -47,11 +47,11 @@ export const Features = () => { - Why dfsync + Why @dfsync/client - A focused foundation for dependable HTTP communication between services — with sensible - defaults, auth strategies, lifecycle hooks and retry support. + A lightweight HTTP client for service-to-service communication, with sensible defaults, + authentication strategies, lifecycle hooks, and retry support. diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index 7e1a8c7..329fd05 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -31,7 +31,7 @@ export const Footer = () => { npm {