Skip to content

FRD: Write and Ratify ADR-062 API Integration

FieldValue
IDFRD-042
OwnerDavid Holmes
StatusDraft
Last Updated2026-05-26
RelatedADR-027 (Default Tech Stack)
Target Releasev2.1.0
TypeInfra
ComplexityM

Document Summary

This FRD covers authoring, reviewing, and ratifying ADR-062, which will codify the platform’s client-side API integration patterns: HTTP client instantiation, auth header injection, retry and timeout strategy, TanStack Query conventions (query keys, stale times, error boundaries), and the mapping from ApiError envelopes to UI error states. ADR-062 is the client-side companion to ADR-061 (API Design).


Introduction

Overview

Frontend code integrates with backend APIs through TanStack Query and a shared HTTP client. The patterns for client setup, auth header injection, retry logic, and error boundary integration are currently implicit conventions copied between features. ADR-062 will make these patterns explicit, reducing boilerplate and ensuring consistent error handling across all API consumers.

Goals

  • Define the canonical HTTP client factory and its configuration (base URL, headers, timeout).
  • Specify how auth tokens are injected into requests (via interceptor, not per-call).
  • Codify retry and timeout strategy (which errors retry, exponential backoff parameters).
  • Standardize TanStack Query patterns: query key factories, stale time defaults, mutation error handling.
  • Define how ApiError envelopes map to error boundaries and toast notifications.

Non-Goals

  • Defining the server-side API shape (covered by ADR-061).
  • Implementing a new HTTP client library.
  • Changing authentication flows (covered by ADR-025).

Scope

In Scope

ItemDescription
ADR-062 MDX documentFull ADR following the project’s ADR template with frontmatter tags.
Client instantiationStandard createApiClient(config) factory pattern.
Auth header injectionBearer token via request interceptor, refresh-on-401 strategy.
Retry strategyRetry on 429 and 5xx, exponential backoff, max 3 retries, no retry on 4xx (except 429).
TimeoutDefault 30-second timeout, configurable per request.
TanStack Query conventionsQuery key factory pattern, default stale times, useQuery/useMutation patterns.
Error boundary integrationApiError mapping to error boundary fallback and inline error states.
ADR routing updateRegenerate docs/adrs/docs-index.json and Storybook Docs/ADRs/Overview.

Out of Scope

ItemReason
Server-side API designCovered by ADR-061.
Offline/cache-first strategiesNot currently needed; can be added as an amendment.
WebSocket or SSE integrationDifferent transport, different ADR.

Users and Pain Points

UserPain Point
Frontend developerMust manually configure auth headers, retry logic, and error mapping for each new feature’s API calls.
Frontend developerTanStack Query key structures are inconsistent, causing cache invalidation bugs.
UX designerError states vary across features because there is no standard mapping from API errors to UI states.
QA engineerCannot predict error behavior because retry and timeout strategies differ per feature.

Definitions

TermDefinition
API clientA configured HTTP client instance (fetch wrapper) with base URL, auth headers, retry logic, and timeout.
Query key factoryA function that produces structured TanStack Query keys for consistent cache addressing (e.g., queryKeys.users.list(filters)).
Error boundaryA React component that catches thrown errors from child components and renders a fallback UI.
Stale timeTanStack Query configuration defining how long cached data is considered fresh before background refetching.

Current State

The codebase uses TanStack Query for data fetching. Individual features create their own fetch wrappers or use a partially-shared client. Current issues:

  • Auth header injection is done per-call in some features and via a shared interceptor in others.
  • Retry logic is absent or inconsistent (some features retry on all errors, some never retry).
  • Query key structures vary: some use flat strings, others use nested arrays, making cross-feature cache invalidation unreliable.
  • Error handling ranges from global error boundary catch-all to per-component try/catch with inconsistent toast messages.
  • No documented stale-time defaults; some queries use 0 (always refetch), others use Infinity (never refetch).

Proposed Solution

Author docs/adr-062-api-integration.mdx covering:

  1. Client factorycreateApiClient({ baseUrl, getAccessToken, timeout?, retryConfig? }) returns a typed client with get, post, put, patch, delete methods. Each method returns Promise<T> and throws ApiError on failure.
  2. Auth injection — The client calls getAccessToken() before each request and sets Authorization: Bearer <token>. On 401 response, it attempts one silent refresh via the auth module, then retries the original request. On second 401, it throws.
  3. Retry strategy — Retry on 429 (respecting Retry-After header) and 5xx errors. Exponential backoff: 1s, 2s, 4s. Max 3 retries. No retry on 400, 401 (after refresh attempt), 403, 404, 409, 422.
  4. TanStack Query conventions — Query key factories follow a [entity, scope, ...params] pattern (e.g., ['users', 'list', { role: 'admin' }]). Default stale time is 30 seconds. Mutations use onSettled to invalidate related queries. throwOnError: true for queries rendered inside error boundaries.
  5. Error mappingApiError.code maps to error boundary (fatal: auth.*, server.*) or inline error state (recoverable: validation.*). Toast notifications use the semantic variant matching the error category.

Requirements

IDPriorityRequirement
API62-01P0ADR-062 MDX file created with full ADR template and frontmatter.
API62-02P0Client factory pattern documented with TypeScript example.
API62-03P0Auth header injection and 401-refresh flow documented.
API62-04P0Retry strategy (which codes, backoff, max retries) specified.
API62-05P0TanStack Query key factory pattern documented with examples.
API62-06P0Error-to-UI mapping rules documented.
API62-07P1Default stale-time table by entity type.
API62-08P1ADR index updated with ADR-062 entry.

Functional Requirements

  1. The ADR must include a complete TypeScript example of a query key factory for a users entity with list, detail, and search scopes.
  2. The ADR must include a sequence diagram or numbered steps for the 401-refresh-retry flow.
  3. The ADR must specify the exact Retry-After header parsing behavior (seconds vs. HTTP-date).
  4. The ADR must define how useMutation onError maps ApiError.code to toast variant (success/warning/destructive/default per ADR semantic toast rules).
  5. The ADR must specify that all query functions throw ApiError (not raw Response or generic Error), enabling typed error boundaries.

Non-Functional Requirements

CategoryRequirement
DiscoverabilityADR frontmatter tags include api and api-integration.
ConsistencyClient factory must produce errors matching apiErrorSchema from api-types.ts.
TestabilityADR specifies that the client factory accepts a fetch override for test mocking.

API/Interface Requirements

The ADR defines the recommended client interface. Example:

interface ApiClient {
get<T>(path: string, params?: Record<string, string>): Promise<T>;
post<T>(path: string, body: unknown): Promise<T>;
put<T>(path: string, body: unknown): Promise<T>;
patch<T>(path: string, body: unknown): Promise<T>;
delete(path: string): Promise<void>;
}

No code changes are introduced by this FRD; the ADR codifies patterns for future implementation.


Accessibility Requirements

Not applicable. This is a governance document. Accessibility requirements for error states are referenced (semantic toasts, inline field errors) but defined elsewhere.


Content and Documentation Requirements

  • ADR-062 written as docs/adr-062-api-integration.mdx.
  • docs/adrs/docs-index.json and Storybook Docs/ADRs/Overview updated with ADR-062.
  • Cross-reference ADR-061 from ADR-062 and vice versa.

Dependencies

DependencyTypeNotes
ADR-061 (API Design)GovernanceADR-062 references the response shapes defined in ADR-061.
ADR-025 (Identity/Auth)GovernanceAuth token lifecycle referenced for the 401-refresh flow.
src/lib/api-types.tsInternalError and pagination types that the client must produce.
TanStack Query v5ExternalQuery and mutation patterns are TanStack Query-specific.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
Opinionated retry strategy may not fit all use cases.MediumLowADR allows per-request retry override via retryConfig parameter.
Query key factory adds boilerplate.MediumLowA createQueryKeys helper reduces per-entity boilerplate to one function call.
401-refresh-retry adds complexity to the client.MediumMediumThe pattern is well-established (axios interceptor pattern). The ADR includes a reference implementation.

Open Questions

  1. Should the client factory be a class or a plain function returning an object? Leaning toward plain function for tree-shaking.
  2. Should the ADR specify a global QueryClient configuration or leave it to each app? Leaning toward a recommended createAppQueryClient() factory.
  3. Should optimistic updates be covered in this ADR or deferred to a separate guide?

Acceptance Criteria

  • docs/adr-062-api-integration.mdx exists with full ADR template and frontmatter tags [api, api-integration].
  • Client factory, auth injection, retry, query keys, and error mapping are documented with TypeScript examples.
  • ADR-061 and ADR-062 cross-reference each other.
  • docs/adrs/docs-index.json and Storybook Docs/ADRs/Overview include ADR-062.
  • pnpm build-storybook passes.

LLM Handoff Instructions

When implementing this FRD:

  1. Check an existing ratified ADR for the frontmatter format and section structure.
  2. Create docs/adr-062-api-integration.mdx with frontmatter: tags: [api, api-integration], applies_when: "Building or reviewing frontend API integration code", status: ratified.
  3. Reference api-types.ts schemas for the error and pagination types. The ADR must not contradict those schemas.
  4. Include a query key factory example using the ['entity', 'scope', params] pattern.
  5. Include the 401-refresh-retry flow as numbered steps.
  6. Run pnpm run docs:index and pnpm run adrs so ADR-062 appears in machine-readable routing and the Storybook overview.
  7. Add a cross-reference to ADR-061 in the Related Decisions section.
  8. Run pnpm build-storybook to confirm the MDX renders.

Decision Log

DateDecisionRationale
2026-05-26Plain function factory over class-based client.Better tree-shaking, simpler testing, consistent with existing library patterns.
2026-05-26Retry only on 429 and 5xx.4xx errors (except 429) indicate client bugs or invalid input; retrying them wastes resources and obscures bugs.
2026-05-2630-second default stale time.Balances freshness against unnecessary refetches. Entity-specific overrides documented in the ADR.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.