Overview
accorudo/client turns a route registry into a typed HTTP client backed by fetch (and XMLHttpRequest for upload progress). Unlike accorudo/core, it ships runtime code.
Creating a client
AccorudoClient is generic over your route registry (see Registering routes):
import { AccorudoClient } from "accorudo/client";
import type { MainRoutes } from "./api";
export const mainApi = new AccorudoClient<MainRoutes>("https://api.example.com");
req
Makes a request and resolves with the parsed JSON response. TypeScript infers pathParams, query, body, headers, and the response type from the (method, path) pair:
const widgets = await mainApi.req("get", "/widget", {
query: { limit: 20, offset: 0 },
});
const widget = await mainApi.req("get", "/widget/:id", {
pathParams: { id: "abc-123" },
});
await mainApi.req("post", "/widget", {
body: { name: "My widget", enabled: true },
});
config also accepts keepalive and signal (AbortSignal).
withProgress
Same signature as req, plus an onProgress callback (0–1) reporting upload progress. Built on XMLHttpRequest since fetch cannot report upload progress. Prefer it for file uploads — see Multipart routes:
await mainApi.withProgress(
"post",
"/widget/:id/media",
{
pathParams: { id: widgetId },
body: { file },
type: RouteType.Multipart,
},
(progress) => {
uploadProgress.value = progress;
}
);
Error handling
Both methods reject with ApiError (an Error subclass carrying status) on a non-2xx response, or on an aborted withProgress call (status: 0):
import { isApiError } from "accorudo/client";
try {
await mainApi.req("get", "/widget/:id", { pathParams: { id } });
} catch (error) {
if (isApiError(error) && error.status === 404) {
// handle not found
}
throw error;
}
Next steps
Both req and withProgress run any registered interceptors before issuing the request — useful for logging, or built-ins like rate limiting.