Files
sdk/sdks/javascript/docs/CACHING_AND_RETRIES.md
2026-05-29 14:39:04 -05:00

2.9 KiB

Caching, Retries, and Failure Semantics

GET lifecycle

  1. Build full URL from baseUrl, path, and query params.
  2. Check cache by full URL.
  3. Fetch with auth headers and timeout on cache miss.
  4. Retry network errors, timeout errors, 429, and 5xx.
  5. Parse JSON.
  6. Throw SocialhoseError for unsupported non-OK responses.
  7. Store successful parsed response in cache.

POST lifecycle

  1. Build URL.
  2. Fetch JSON body with auth headers and timeout.
  3. Retry network errors, timeout errors, 429, and 5xx.
  4. Parse JSON.
  5. Return { status, data }.
  6. Never cache.

Retry policy

Defaults:

retries: 3,
retryDelayMs: (attempt) => 400 * 2 ** attempt + Math.random() * 200,
timeoutMs: 8_000,

Retries apply to transient conditions only:

  • network failures
  • SDK timeout/abort failures
  • 429 Too Many Requests
  • 5xx server errors

Retries do not apply to normal client errors such as 400, 401, 403, and 404.

Cache contract

interface Cache {
  get(key: string): Promise<unknown | undefined>;
  set(key: string, value: unknown, ttlMs: number): Promise<void>;
  delete(key: string): Promise<void>;
}

The cache key is the full request URL. ttlMs is in milliseconds and comes from cacheTtlMs or per-request revalidateSeconds. A non-positive ttlMs means "do not cache"; built-in caches delete/skip the entry rather than storing it forever.

Redis-style cache example

import { SocialhoseClient, type Cache } from '@socialhose/api';

class RedisJsonCache implements Cache {
  constructor(private redis: {
    get(k: string): Promise<string | null>;
    set(k: string, v: string, mode: 'PX', ttl: number): Promise<unknown>;
    del(k: string): Promise<unknown>;
  }) {}

  async get(key: string) {
    const value = await this.redis.get(key);
    return value == null ? undefined : JSON.parse(value);
  }

  async set(key: string, value: unknown, ttlMs: number) {
    if (ttlMs <= 0) return;
    await this.redis.set(key, JSON.stringify(value), 'PX', ttlMs);
  }

  async delete(key: string) {
    await this.redis.del(key);
  }
}

const socialhose = new SocialhoseClient({
  apiKey: process.env.SOCIALHOSE_API_KEY!,
  cache: new RedisJsonCache(redis),
});

Method failure semantics

Campaign, analytics, mention, and list methods:

  • Throw SocialhoseError after retry exhaustion or unsupported non-OK responses.
  • Return normalized arrays when the API wraps arrays in properties such as series, platforms, or keywords.

inviteMailingListMember():

  • 201 + status: invited -> outcome: 'invited'.
  • 409 -> outcome: 'already'.
  • Unexpected success/conflict shapes -> outcome: 'error'.
  • Other non-OK statuses throw.

Entity methods:

  • getEntityBrief() throws if the mention search fails.
  • getEntityStats() requires the initial brief but treats later subrequests as best-effort.
  • getEntityBriefs() skips failed terms and returns successful entries.