TypeScript client
A TypeScript client, @tourpingo/client, is built
(issue #486) and
generated from the published contract, so its types are the API’s. It is a
small fetch client with no runtime dependencies:
createClient({ baseUrl, publishableKey })makes a client; a server can pass a secret key instead.call(operationId, input)takes an operation’s id from the spec and itspath,queryandheaderparameters andbody, all typed, with the API’s snake_case field names.- It never throws for an answer: you get
ok: truewithstatusand typeddata, orok: falsewithstatusand theproblem. A network failure is a problem with status 0 and the codeNetworkError.
It isn’t published to npm yet; that is still to be decided. When it is, this page will say how to install it.
Meanwhile
Section titled “Meanwhile”Every example in these guides has a TypeScript tab that uses fetch, which
Node, Bun, Deno and Cloudflare Workers all have. To type the answers, you
can generate types from the spec with any OpenAPI 3.1 tool:
- the whole spec:
/openapi.yaml; - only the public API, for a website:
/openapi-public.json.
Wrap fetch once, so every call sends the key and every error becomes one
type you can switch on by code:
type Problem = { status: number; code: string; detail: string; [field: string]: unknown }
export class TourpingoError extends Error { constructor(readonly problem: Problem) { super(`${problem.code}: ${problem.detail}`) }}
export const tourpingo = async <T>(path: string, init: RequestInit = {}): Promise<T> => { const res = await fetch(new URL(path, process.env.TP_API_URL), { ...init, headers: { "Tp-Publishable-Key": process.env.TP_KEY ?? "", "Content-Type": "application/json", ...init.headers }, }) const body = res.status === 204 ? null : await res.json() if (!res.ok) throw new TourpingoError(body as Problem) return body as T}