Skip to content

UI for Admin — Setup

The admin UI uses Orval to auto-generate the following from the Admin API's OpenAPI 3.1 spec (/api/v1/doc):

  • TypeScript types (request / response / components)
  • TanStack Query hooks (useGetAdmins, useCreateAdmin, etc.)
  • Zod schemas (used for form validation)

Orval Configuration

// orval.config.ts
export default {
  adminApi: {
    input: 'http://localhost:8080/api/v1/doc',
    output: {
      target: 'src/api/generated/admin.ts',
      client: 'react-query',
      schemas: 'src/api/generated/model',
      httpClient: 'fetch',
      override: {
        mutator: { path: 'src/api/client.ts', name: 'adminFetcher' },
      },
    },
  },
  adminApiZod: {
    input: 'http://localhost:8080/api/v1/doc',
    output: {
      target: 'src/api/generated/admin.zod.ts',
      client: 'zod',
    },
  },
}

Fetcher (src/api/client.ts)

  • Routes to /api/proxy/<path> on the same origin (does not access the Admin API directly)
  • Sends httpOnly cookies automatically via credentials: 'same-origin'
  • Response envelope normalization: The Admin API mixes { success, data } and legacy top-level formats (see API for Admin). The fetcher absorbs the wrapper so hooks always receive an unwrapped payload
  • 401 retry: When /api/proxy/<path> returns a 401, a single in-flight refresh Promise is created to coalesce parallel requests. On success, the original request is replayed
// src/api/client.ts
let refreshPromise: Promise<void> | null = null

export async function adminFetcher<T>(config: AdminFetchConfig): Promise<T> {
  const res = await fetchWithCookies(config)
  if (res.status !== 401) return normalizeEnvelope(res)

  refreshPromise ??= refreshSession().finally(() => { refreshPromise = null })
  await refreshPromise

  const retried = await fetchWithCookies(config)
  return normalizeEnvelope(retried)
}

Regenerating the API Client

Command Purpose
bun run generate:api During local development. Start the Admin API with bun run dev-admin before running
CI check Compares generated output against the OpenAPI spec. Build fails if they do not match

How to Obtain the OpenAPI Spec (Cross-Repository Integration)

Because the Admin API lives in a separate repository (GenAI-Guinness-backend), a strategy for fetching the OpenAPI spec must be established.

Approach Timing Pros / Cons
Start the local backend and fetch from it During development Reflects the latest spec immediately. Requires developers to set up the backend
Backend CI publishes the OpenAPI JSON as an artifact; UI side pins the version Staging and beyond Reproducible. Risk of version drift

Default policy: Use approach 1 during development. Switch to approach 2 once the backend stabilizes at v1.