Packages
api-client
The platform-neutral JSON transport shared by web and Expo.
statshub-api-client owns HTTP behavior that must agree across the browser,
Next.js, and React Native. It has no React, Next.js, Expo, Supabase, or Better
Auth dependency.
Exports
| Export | Type | Description |
|---|---|---|
createHttpClient | function | Creates a client with get, post, put, patch, delete, and request methods. |
buildUrl | function | Joins a base URL and path, drops nullish query values, and serializes arrays as comma-separated values. |
readResponseBody | function | Reads empty, JSON, plain-text, and HTML bodies without losing the original text. |
ApiError | class | Carries the HTTP status, URL, and parsed body. Status 0 means no response arrived. |
isAbortError | function | Recognises browser cancellation and React Native's released-response cancellation error. |
HttpClientConfig
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
baseUrl | string | No | same-origin path | Prefix for every request path. |
fetch | (url, init) => Promise<Response> | No | global fetch | Adapter used by Next.js to add cache metadata and by tests to supply responses. |
headers | HeadersInit | No | none | Headers applied to every request. |
getHeaders | () => HeadersInit | Promise<HeadersInit> | No | none | Request-scoped cookie or bearer headers. Called for every request. |
unwrapData | boolean | No | false | Returns the value inside a successful { data: value } body. |
Header precedence is fixed: static client headers, then getHeaders, then the
JSON content type, then request headers. A caller can override any earlier
value for one request.
Request behavior
| Condition | Result |
|---|---|
undefined or null query value | Omitted from the URL. |
| Array query value | One comma-separated query value. |
| Body is present | JSON encoded with Content-Type: application/json. |
| Empty successful body | Resolves as undefined. |
| Non-2xx response | Throws ApiError with the parsed body. |
| Network failure | Throws ApiError with status 0. |
| Aborted request | Preserves AbortError; never reports it as a network failure. |
Example
import { createHttpClient } from "statshub-api-client";
const api = createHttpClient({
baseUrl: "https://www.statshub.com/api",
});
const fixtures = await api.get<{ data: unknown[] }>("/event/by-date", {
query: { startOfDay: 1787950800, endOfDay: 1788037200 },
});Platform adapters
| Consumer | Adapter responsibility |
|---|---|
| Web Server Components | Adds Next.js revalidation tags. Private reads inject the complete Supabase cookie header and use no-store. |
| Web client components | Gives SWR a same-origin get or post function. |
| Expo | Supplies the absolute API origin. The StatsHub-specific client keeps its Cloudflare backoff and cached-5xx retry. |
getHeaders is an authentication seam, not an identity provider. Both apps
sign in against the same Supabase project, and the Go API validates that
identity in either shape — web sends the @supabase/ssr cookie, Expo sends the
access token as a bearer header. Sharing the interface is not what makes them
compatible; sharing the project is.
Errors
| Error | Condition |
|---|---|
ApiError with status 0 | Fetch failed before an HTTP response arrived. |
ApiError with status 400–599 | The server returned a non-success status. |
AbortError | The caller cancelled the request. |
Related
- Web data — Next.js cache and SWR adapters.
- Expo data — React Query resources and API-specific retries.
- API contract — response compatibility between API implementations.