@ipetsadmin/api-client
v1.8.0
Published
Client used to interact with Truffa project API
Downloads
901
Readme
@ipetsadmin/api-client
Typed HTTP client for the Truffa API. Consumed by web and mobile apps. No baked-in base URL: pass a preconfigured HTTP layer (typically an Axios instance with baseURL set). Request and response shapes come from @ipetsadmin/contracts.
Requirements
- Node.js ≥ 18.18
- Peer dependency:
@ipetsadmin/contracts≥ 1.3.0 (auth, profile, pets, treatments:PetResponse,CreateTreatmentInput,TreatmentResponse,IApiResponse, etc.). Use a contracts version that includes every DTO you call.
Installation
pnpm add @ipetsadmin/api-client @ipetsadmin/contracts
# or
npm install @ipetsadmin/api-client @ipetsadmin/contractsWhat ships today
| Export | Description |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| createApiClient(options) | Factory returning healthCheck, auth, users, and pets namespaces |
| ApiClient / CreateApiClientOptions | Typed client and { http: HttpClient } options |
| HttpClient | get, post, patch, and put (minimal surface compatible with Axios) |
| HttpGet / HttpPost / HttpPatch / HttpPut | Method signatures |
| Named helpers | Same calls as the factory — see auth.ts, health-check.ts, user.ts, pet.ts |
Parity with @ipetsadmin/api-main
The API surfaces below are covered by this client (see api-main server.ts and route modules under routes/):
| Area | Server routes this client implements |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Health | GET /api/v1/health-check |
| Auth | Routes under /api/v1/auth/… |
| Users | GET / PATCH /api/v1/users/me/profile; GET / POST /api/v1/users/{userId}/pets |
| Pets | GET / PUT /api/v1/pets/{petId}; GET / POST /api/v1/pets/{petId}/treatments; GET /api/v1/pets/{petId}/treatments/{treatmentId} |
api-main also serves OpenAPI (/api-docs, /api-docs.json) when enabled; that is not wrapped here.
Endpoints
| HTTP | Path | createApiClient | Named helper |
| ------- | ------------------------------------------------- | ----------------------------------------------------------- | -------------------------------------------------------- |
| GET | /api/v1/health-check | client.healthCheck() | fetchHealthCheck(http) |
| POST | /api/v1/auth/register | client.auth.register(body) | postRegister(http, body) |
| POST | /api/v1/auth/login | client.auth.login(body) | postLogin(http, body) |
| GET | /api/v1/auth/oauth/google/start?redirectUri=... | client.auth.getGoogleOAuthStart(redirectUri) | getGoogleOAuthStart(http, redirectUri) |
| POST | /api/v1/auth/oauth/google/callback | client.auth.postGoogleOAuthCallback(body) | postGoogleOAuthCallback(http, body) |
| POST | /api/v1/auth/refresh | client.auth.refresh(body) | postRefresh(http, body) |
| POST | /api/v1/auth/logout | client.auth.logout(body) | postLogout(http, body) |
| PATCH | /api/v1/auth/verify-email | client.auth.verifyEmail(body) | patchVerifyEmail(http, body) |
| GET | /api/v1/auth/me | client.auth.me(accessToken) | getMe(http, accessToken) |
| GET | /api/v1/users/me/profile | client.users.getProfile(accessToken) | getUserProfile(http, accessToken) |
| PATCH | /api/v1/users/me/profile | client.users.patchProfile(accessToken, body) | patchUserProfile(http, accessToken, body) |
| GET | /api/v1/users/{userId}/pets | client.users.getPets(accessToken, userId) | getUserPets(http, accessToken, userId) |
| POST | /api/v1/users/{userId}/pets | client.users.createPet(accessToken, userId, body) | createUserPet(http, accessToken, userId, body) |
| GET | /api/v1/pets/{petId} | client.pets.getById(accessToken, petId) | getPetDetails(http, accessToken, petId) |
| PUT | /api/v1/pets/{petId} | client.pets.update(accessToken, petId, body) | putPetDetails(http, accessToken, petId, body) |
| GET | /api/v1/pets/{petId}/treatments | client.pets.getTreatments(accessToken, petId) | getPetTreatments(http, accessToken, petId) |
| POST | /api/v1/pets/{petId}/treatments | client.pets.createTreatment(accessToken, petId, body) | createPetTreatment(http, accessToken, petId, body) |
| GET | /api/v1/pets/{petId}/treatments/{treatmentId} | client.pets.getTreatment(accessToken, petId, treatmentId) | getPetTreatment(http, accessToken, petId, treatmentId) |
Responses use IApiResponse<T> from contracts (success, data, etc.). Auth session payloads are AuthSessionResponse (TokenPair + user). logout returns 204 with no JSON body. verifyEmail success envelope matches the server (typically data may be empty). User profile responses use IApiResponse<UserProfileResponse>; PATCH must not send avatar (API rejects it).
Pets: IApiResponse<PetResponse> for single-pet calls; PetResponse is the same shape as IPet. Create pet under a user uses PostUserPetRequestBody (no ownerId / createdAt / updatedAt in JSON — the API fills those). Treatments use TreatmentResponse; create body is PostPetTreatmentRequestBody (no petId; optional status). PUT pet uses PutPetDetailsBody (partial fields only).
Usage example (Axios)
Paths are relative to baseURL (e.g. https://api.example.com).
import axios from 'axios';
import { createApiClient } from '@ipetsadmin/api-client';
const http = axios.create({
baseURL: process.env.API_BASE_URL,
timeout: 30_000,
headers: { 'Content-Type': 'application/json' },
});
const api = createApiClient({ http });
const health = await api.healthCheck();
const session = await api.auth.login({ email: '[email protected]', password: '********' });
// session — IApiResponse<AuthSessionResponse>; with Axios, the HTTP body is axiosResponse.dataFor IApiResponse<AuthSessionResponse>, the envelope is the JSON body; the AuthSessionResponse is usually response.data.data (outer data = Axios, inner data = API payload), depending on typings.
OAuth (mobile / web)
- Call
getGoogleOAuthStartwith the sameredirectUriyou registered in Auth0 and in the API’sOAUTH_ALLOWED_REDIRECT_URIS. - Open
authorizationUrlin a browser /ASWebAuthenticationSession. - After redirect, send
code,state, andredirectUriwithpostGoogleOAuthCallback.
Email verification
Call api.auth.verifyEmail({ token }) (or patchVerifyEmail) with the one-time token from the verification link your backend emails. Shapes: VerifyEmailRequest from @ipetsadmin/contracts.
User profile (authenticated)
After you have an access JWT (e.g. from login or register), read or update the persisted profile (not the same shape as lightweight /auth/me — includes role, isActive, full profile object):
const prof = await api.users.getProfile(accessToken);
await api.users.patchProfile(accessToken, { firstName: 'Alex', lastName: 'Kim' });Pets and treatments (authenticated)
import { TreatmentType } from '@ipetsadmin/contracts';
const pets = await api.users.getPets(accessToken, userId);
const pet = await api.pets.getById(accessToken, petId);
await api.pets.update(accessToken, petId, { description: 'Updated notes' });
const list = await api.pets.getTreatments(accessToken, petId);
const created = await api.pets.createTreatment(accessToken, petId, {
ownerId: userId,
medicationName: 'Example',
dosage: '1 tablet',
frequencyHours: 12,
durationDays: 7,
totalDoses: 14,
treatmentType: TreatmentType.MEDICATION,
});
const one = await api.pets.getTreatment(accessToken, petId, created.data!.id);Or use the named helpers from ./endpoints/pet / ./endpoints/user.
Why a factory?
createApiClient({ http }) keeps env and transport out of this package, supports multiple backends in one app, and makes tests easy with a mock http object.
Architecture
HttpClient— abstraction overget/post/patch/put({ data: T }response shape, Axios-compatible).src/endpoints/*.ts— thin functions:(http, …args) => Promise<…>.createApiClient— wireshttpinto those endpoints underhealthCheck,auth,users, andpets.@ipetsadmin/contracts— DTOs (RegisterRequest,AuthSessionResponse,PetResponse,CreateTreatmentInput, …).
Extending further
Add methods on HttpClient in src/http-client.ts, then new endpoint modules. For query params, headers, and Authorization, align with your adapter (Axios passes a config object to get, post, patch, and put; getMe and pet routes set Authorization: Bearer for the access token argument).
Testing
Inject a fake HttpClient with get, post, patch, and put mocks and assert URLs and payloads.
import type { HttpClient } from '@ipetsadmin/api-client';
import { createApiClient } from '@ipetsadmin/api-client';
const http: HttpClient = {
get: jest.fn().mockResolvedValue({ data: { success: true, data: {} } }),
post: jest.fn().mockResolvedValue({ data: { success: true, data: {} } }),
patch: jest.fn().mockResolvedValue({ data: { success: true } }),
put: jest.fn().mockResolvedValue({ data: { success: true, data: {} } }),
};
const api = createApiClient({ http });
await api.healthCheck();
expect(http.get).toHaveBeenCalledWith('/api/v1/health-check', undefined);
await api.users.getProfile('token');
expect(http.get).toHaveBeenCalledWith('/api/v1/users/me/profile', {
headers: { Authorization: 'Bearer token' },
});Development (this repository)
| Script | Purpose |
| ------------------------- | ------------------------------------ |
| pnpm run build | tsup → dist/ (CJS, ESM, .d.ts) |
| pnpm run typecheck | tsc --noEmit |
| pnpm run lint | ESLint |
| pnpm run validate | typecheck + lint + Prettier check |
| pnpm run prepublishOnly | validate + build before publish |
Changelog
See CHANGELOG.md.
License
MIT — see LICENSE.
