API Conventions

Prev Next

API Conventions

These conventions reflect patterns in the current codebase (GraphQL client usage, fetch helpers, middleware, and Next.js API routes). Treat them as defaults for new endpoints and clients.

Transports and base URLs

  • Use getApiBaseUrl() plus constants in src/config/endpoints.ts to build URLs; avoid hard-coded strings.
  • Management and identity use GraphQL at Endpoints.Management.GraphQL; invoke-style REST endpoints live under Endpoints.Invoke and feature-specific entries (content, monetization, admin).
  • Internal Next.js APIs (for example, /api/device) should be called with absolute URLs via Fetch.json({ absolute }) to bypass base URL resolution.

Authentication and headers

  • Auth headers come from cookies (vl-accessToken, managementXApiKey) via getAuthHeadersOnClient() and are automatically attached by Fetch.json and the GraphQL client auth link.
  • Route middleware (src/proxy.ts) enforces login and permission checks; API clients should rely on that instead of duplicating gate logic.
  • Default to Content-Type: application/json; CORS responses must include Access-Control-Allow-Origin mirroring the request origin and limit methods to what is supported.

Clients and helpers

  • Use Fetch.json for REST/HTTP calls. It enforces JSON-only content types, attaches auth headers, and normalizes upstream errors into AppError.
  • Use GraphQLClient.query / GraphQLClient.mutate (Apollo) for GraphQL operations; they are client-only (guarded by window checks) and should be wrapped with AsyncHandler.run to normalize errors.
  • Avoid raw fetch or ad-hoc Apollo clients; centralize behavior through the helpers to keep auth, error handling, and content-type checks consistent.

Error handling

  • Normalize all failures to AppError using AppError.create / AppError.from; never throw plain errors from API layers.
  • Use stable error codes from src/constants/errorMap.ts; codes are never reused, messages are safe for clients, and HTTP status represents transport semantics only.
  • Wrap async calls with AsyncHandler.run(fn, args, fallbackCode) to apply consistent fallback codes and shape.

Request semantics

  • Use JSON bodies and explicit methods; avoid sending bodies with GET (the fetch helper already skips bodies for GET).
  • Set cache: no-store for identity and permission-sensitive calls (see getUserRoles); set explicit cache headers on API routes that must not be cached (for example, /api/device).
  • Prefer idempotent GET for fetches, POST for mutations; align GraphQL operations with their intent (queries for reads, mutations for writes).

Pagination, sorting, filtering

  • Use offset-based pagination with limit and offset query params (patterns in Endpoints.Monetization.Plans and content list URLs).
  • Sorting params follow orderBy and order (DESC/ASC) where supported; do not invent new names.
  • Filters should be additive and expressed as query params; avoid overloading body payloads for filter semantics.

Response shape and content

  • Return JSON objects; avoid wrapped envelopes unless required by upstream contracts.
  • For GraphQL, surface data as returned by the schema; handle errors responses explicitly and map them to AppError.
  • Include Vary: Origin, Accept-Encoding when responses differ by origin to keep caches correct.

Versioning and paths

  • Keep path prefixes and versions consistent with Endpoints (for example, /v3.0, /v4.0, /management/graphql).
  • Do not introduce new versioned paths without updating Endpoints and calling code; prefer adding entries rather than inline strings.

Safety and invariants

  • GraphQL client and helpers are client-only; server-side usage should go through server-safe utilities or backend services.
  • Do not bypass middleware-based permission checks by calling management APIs from unauthenticated contexts.
  • Treat cookies as the single source for auth header propagation; avoid duplicating token storage in localStorage.