@cactus-agents/api-client
HTTP client framework-agnostic baseado em fetch. Gerencia headers de tenant, idioma, autorização e callbacks de erro.
Instalação
pnpm add @cactus-agents/api-client
Uso básico
import { createApiClient } from '@cactus-agents/api-client';
const client = createApiClient({
baseUrl: 'https://api.example.com/v2',
tenant: 'my-tenant',
language: 'pt-br',
});
const response = await client.get<MyData>('/endpoint');
// response.data, response.status, response.headers
ApiClientConfig
interface ApiClientConfig {
baseUrl: string; // URL base da API
tenant: string; // Header tenant
language: string; // Idioma fallback
// Opcionais
buildId?: string; // ID do build
debug?: boolean; // Habilita header DEBUG
// Callbacks de dados
getAccessToken?: () => string | null;
getLocale?: () => string;
getOriginAccess?: () => OriginAccess;
getReferrerInfo?: () => ReferrerInfo | null;
getExtraHeaders?: () => Record<string, string>;
// Hooks de erro
onUnauthorized?: (url: string) => void; // 401
onChallenge?: () => void; // 429
onTimeoutLimit?: (url: string) => void; // 202
}
Métodos
| Método | Descrição |
|---|---|
get<T>(path, options?) | GET com headers internos |
post<T>(path, body?, options?) | POST com headers internos |
put<T>(path, body?, options?) | PUT com headers internos |
patch<T>(path, body?, options?) | PATCH com headers internos |
delete<T>(path, options?) | DELETE com headers internos |
getExternal<T>(url, options?) | GET para URLs externas (sem headers internos) |
Headers automáticos
Em toda request interna, o client adiciona:
tenant— valor do configlang/language— dogetLocale()ou fallbackversion— buildIdorigin-domain— hostnameX-LOG-INFO— JSON com metadataAuthorization: Bearer {token}— segetAccessToken()retorna tokenX-ORIGIN-ACCESS— segetOriginAccess()retorna valor
Tratamento de status
| Status | Comportamento |
|---|---|
| 200-299 | Resolve com ApiResponse<T> |
| 202 | Resolve (não throw) + chama onTimeoutLimit |
| 401 | Chama onUnauthorized + throw |
| 429 | Chama onChallenge + throw |
| Outros non-ok | Throw |
ApiResponse
interface ApiResponse<T> {
data: T;
status: number;
statusText: string;
headers: Headers;
}
OriginAccess
enum OriginAccess {
Unknown,
App,
Desktop,
DesktopApp,
Mobile,
MobileApp,
}
Helpers
O pacote exporta helpers de conveniência para quem consome o ApiClient junto com outros pacotes do SDK.
createFetcherFromClient(client)
Converte um ApiClient (ou qualquer objeto com get/post que retorna { data }) no formato de fetcher plano esperado por @cactus-agents/auth e @cactus-agents/brand:
import { createApiClient, createFetcherFromClient } from '@cactus-agents/api-client';
import { createAuthService } from '@cactus-agents/auth';
const client = createApiClient({ baseUrl, tenant, language });
const fetcher = createFetcherFromClient(client);
const auth = createAuthService(fetcher);
Na maioria dos casos, prefira usar
createAuthFromClientoucreateBrandFromClientdiretamente — eles fazem essa conversão internamente.
createFullFetcherFromClient(client)
Versão estendida do createFetcherFromClient que expõe todos os 5 métodos HTTP (get, post, put, patch, delete). Usado por pacotes que precisam de mais do que get/post, como @cactus-agents/user:
import { createApiClient, createFullFetcherFromClient } from '@cactus-agents/api-client';
import { createUserService } from '@cactus-agents/user';
const client = createApiClient({ baseUrl, tenant, language });
const fetcher = createFullFetcherFromClient(client);
const user = createUserService(fetcher);
Na maioria dos casos, prefira usar
createUserFromClientdiretamente — ele faz essa conversão internamente.
extractApiError(err)
Normaliza erros do ApiClient (que não são instâncias de Error) em uma estrutura consistente para logging e respostas HTTP:
import { extractApiError } from '@cactus-agents/api-client';
try {
await client.post('/endpoint', body);
} catch (err) {
const { status, data, message, isApiError } = extractApiError(err);
// status: number | undefined
// data: response body (se API error)
// message: string (para logging)
// isApiError: boolean
}
Tipos
interface ClientLike {
get<T>(path: string): Promise<{ data: T }>;
post<T>(path: string, body?: unknown): Promise<{ data: T }>;
}
interface FullClientLike extends ClientLike {
put<T>(path: string, payload?: unknown): Promise<{ data: T }>;
patch<T>(path: string, payload?: unknown): Promise<{ data: T }>;
delete<T>(path: string, payload?: unknown): Promise<{ data: T }>;
}
interface ExtractedApiError {
status: number | undefined;
data: unknown;
message: string;
isApiError: boolean;
}