Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.law4devs.eu/llms.txt

Use this file to discover all available pages before exploring further.

Exception hierarchy

All errors thrown by the SDK extend Law4DevsError, which itself extends the built-in Error. Use instanceof checks to handle specific error types.
Law4DevsError
├── NotFoundError     (HTTP 404)
├── ValidationError   (HTTP 422)
├── RateLimitError    (HTTP 429)
└── ServerError       (HTTP 5xx)
Every error class exposes a statusCode property with the underlying HTTP status code.
import {
  Law4DevsError,
  NotFoundError,
  ValidationError,
  RateLimitError,
  ServerError,
} from 'law4devs';

Basic try/catch

try {
  const article = await client.articles.get('gdpr', 999);
  console.log(article.title);
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error(`Not found (${err.statusCode}): ${err.message}`);
  } else if (err instanceof ValidationError) {
    console.error(`Invalid request (${err.statusCode}): ${err.message}`);
  } else if (err instanceof RateLimitError) {
    console.error(`Rate limited (${err.statusCode}) — all retries exhausted`);
  } else if (err instanceof ServerError) {
    console.error(`Server error (${err.statusCode}) — all retries exhausted`);
  } else if (err instanceof Law4DevsError) {
    console.error(`API error (${err.statusCode}): ${err.message}`);
  } else {
    throw err; // network error or unexpected — re-throw
  }
}

Auto-retry behaviour

The SDK automatically retries on RateLimitError (429) and ServerError (5xx) using exponential backoff with jitter. Only after all retries are exhausted is the error thrown to your code.
// Configure retry behaviour at construction time
const client = new Law4DevsClient({
  maxRetries: 3,    // default: 3 — set to 0 to disable retries
  timeout: 30000,   // ms — each individual attempt has this timeout
});
Timeouts are enforced via AbortController, so they apply per-attempt (not across all retries combined).
NotFoundError and ValidationError are never retried — they indicate client-side issues that will not resolve on retry.

TypeScript narrowing with a typed helper

Define a safeGet helper to return a typed result or a structured error without propagating exceptions:
import { Law4DevsClient, NotFoundError, Law4DevsError, Article } from 'law4devs';

type Result<T> =
  | { ok: true; value: T }
  | { ok: false; error: Law4DevsError };

async function safeGet<T>(fn: () => Promise<T>): Promise<Result<T>> {
  try {
    return { ok: true, value: await fn() };
  } catch (err) {
    if (err instanceof Law4DevsError) {
      return { ok: false, error: err };
    }
    throw err; // unexpected — re-throw
  }
}

// Usage
const result = await safeGet(() => client.articles.get('gdpr', 5));

if (result.ok) {
  console.log(result.value.title); // TypeScript knows result.value is Article
} else {
  if (result.error instanceof NotFoundError) {
    console.log('Article does not exist');
  } else {
    console.error(`Unexpected error: ${result.error.message}`);
  }
}

Handling errors inside for await

Errors thrown during iter() or iterDeadlines() are propagated out of the for await loop. Wrap the loop in try/catch to handle them:
try {
  for await (const article of client.articles.iter('gdpr')) {
    console.log(article.title);
  }
} catch (err) {
  if (err instanceof RateLimitError) {
    console.error('Rate limit hit during iteration — consider reducing perPage or adding delays');
  } else {
    throw err;
  }
}

Error reference

ClassHTTP StatusWhen thrownRetried?
NotFoundError404Requested resource does not existNo
ValidationError422Invalid parameters or queryNo
RateLimitError429Too many requestsYes
ServerError5xxServer-side errorYes
Law4DevsErroranyBase class — catch-allDepends
After all retries are exhausted, RateLimitError and ServerError are thrown normally. Always include these in your catch blocks for production code.