Using the API Client
Make type-safe API calls with the generated client.
The generated api.client.ts provides a fully-typed HTTP client with Result-based error handling.
Basic Usage
Import and use the API client:
import { api } from "./app/services/api/api.client";
// GET request
const { data, error } = await api.get("/users");
// POST request with body
const { data, error } = await api.post("/users", {
name: "John Doe",
email: "john@example.com",
});
// PUT request
const { data, error } = await api.put("/users/{id}",
{ name: "Jane Doe" },
{ id: "123" }
);
// DELETE request
const { data, error } = await api.delete("/users/{id}", { id: "123" });
// PATCH request
const { data, error } = await api.patch("/users/{id}",
{ name: "Updated Name" },
{ id: "123" }
);Path Parameters
For paths with parameters like /users/{id}, pass them as the last argument:
// Single path parameter
const { data, error } = await api.get("/users/{id}", { id: "123" });
// Multiple path parameters
const { data, error } = await api.get("/users/{userId}/posts/{postId}", {
userId: "123",
postId: "456",
});Path parameters are type-safe—TypeScript will error if you miss a required parameter:
// TypeScript error: missing 'id' property
const { data, error } = await api.get("/users/{id}");
// Correct
const { data, error } = await api.get("/users/{id}", { id: "123" });Query Parameters
Pass query parameters via the config.params option:
const { data, error } = await api.get("/users", {
params: {
limit: 10,
offset: 0,
sort: "createdAt",
},
});Query parameters are typed based on your OpenAPI spec:
// If your spec defines:
// GET /users?limit=int&offset=int&search=string
const { data, error } = await api.get("/users", {
params: {
limit: 10, // number
offset: 0, // number
search: "john", // string
},
});Request Bodies
For POST, PUT, and PATCH requests, the body type is inferred from your OpenAPI spec:
// Body type is inferred from your spec
const { data, error } = await api.post("/users", {
name: "John Doe", // Required
email: "john@example.com", // Required
bio: "Developer", // Optional
});TypeScript catches invalid bodies:
// TypeScript error: 'email' is required
const { data, error } = await api.post("/users", {
name: "John Doe",
});Response Types
Response data is fully typed based on your OpenAPI spec:
const { data, error } = await api.get("/users/{id}", { id: "123" });
if (error) {
return;
}
// data is typed based on your spec
console.log(data.id); // Typed
console.log(data.name); // Typed
console.log(data.email); // Typed
console.log(data.unknown); // TypeScript errorResult-Based Error Handling
All API calls return a Result type instead of throwing:
type Result<T> =
| { data: T; error: null } // Success
| { data: null; error: ApiError }; // FailureThis makes error handling explicit:
const { data, error } = await api.get("/users/{id}", { id: "123" });
if (error) {
// Handle error
console.error(error.message);
console.error(error.code); // "NOT_FOUND", "UNAUTHORIZED", etc.
console.error(error.status); // HTTP status code
return;
}
// TypeScript knows data is not null here
console.log(data.name);See Error Handling for detailed error handling patterns.
Additional Axios Config
Pass additional Axios configuration as the last argument:
// With timeout
const { data, error } = await api.get("/users", {
timeout: 5000,
});
// With custom headers
const { data, error } = await api.get("/users", {
headers: {
"X-Custom-Header": "value",
},
});
// With path params and config
const { data, error } = await api.get("/users/{id}",
{ id: "123" },
{ timeout: 5000 }
);Method Signatures
GET
// Without path params
api.get<Path>(url, config?)
// With path params
api.get<Path>(url, pathParams, config?)POST
// Without path params
api.post<Path>(url, body, config?)
// With path params
api.post<Path>(url, body, pathParams, config?)PUT
// Without path params
api.put<Path>(url, body, config?)
// With path params
api.put<Path>(url, body, pathParams, config?)DELETE
// Without path params
api.delete<Path>(url, config?)
// With path params
api.delete<Path>(url, pathParams, config?)PATCH
// Without path params
api.patch<Path>(url, body, config?)
// With path params
api.patch<Path>(url, body, pathParams, config?)Real-World Example
import { api } from "./api/api.client";
export async function getUser(id: string) {
const { data, error } = await api.get("/users/{id}", { id });
if (error) {
if (error.code === "NOT_FOUND") {
return null;
}
throw new Error(error.message);
}
return data;
}
export async function createUser(input: { name: string; email: string }) {
const { data, error } = await api.post("/users", input);
if (error) {
if (error.code === "VALIDATION_ERROR") {
throw new Error(`Validation failed: ${error.message}`);
}
throw new Error(error.message);
}
return data;
}
export async function listUsers(options?: { limit?: number; offset?: number }) {
const { data, error } = await api.get("/users", {
params: options,
});
if (error) {
throw new Error(error.message);
}
return data;
}