Extend

Create a TypeScript Client Wrapper

Build and ship your own TypeScript client wrapper using the types and the route metadata @kizunajs/fetch carries.

Beta

The wrapper surface is new and still settling. The types @kizunajs/fetch exports may change while v2 is in beta, so pin your version if you depend on it.

A wrapper builds on the fetch client your app already has, the one kizuna generate writes. Wrap it to build hooks, an SDK layer, or any other integration. @kizunajs/tanstack-query is one of these, and it takes the client and nothing else.

Whether a client goes first-party comes down to demand, not age. If it is something most teams on Kizuna would reach for, we will add it. What we will not take on is one a handful of people need, since we maintain everything we merge. The client API is public, so you can build and publish your own today.

Pattern

src/lib/my-client.ts
import { apiClient } from './api-client';

export function createMyClient() {
    return {
        getUser: (id: string) =>
            apiClient.users.getUser({
                params: {
                    id,
                },
            }),
        createUser: (data: Parameters<typeof apiClient.users.createUser>[0]['body']) =>
            apiClient.users.createUser({
                body: data,
            }),
    };
}

Reading the route off a method

A wrapper that treats routes generically, rather than naming each one, needs to know what each method answers: its method, its path, which statuses it declares. Every client method carries its own route, and routeOf reads it:

import { routeOf } from '@kizunajs/fetch';

const route = routeOf(apiClient.users.getUser);

route?.method; // 'GET'
route?.path; // '/users/:id'

This is what lets a wrapper take the client alone. A GET gets query semantics, anything else gets mutation semantics, and the declared statuses say which responses are data. routeOf answers undefined for anything that is not a client method, so a group or a stray value is easy to skip while walking the client.

Types

The types from @kizunajs/fetch:

TypeDescription
Client<T, Codes>The full typed client shape for a set of routes
ClientArgs<Route>What one route's method accepts: params, query, body, headers
ClientResponse<Route, Codes>The discriminated union one route's method resolves to
ClientConfigWhat createClient takes

These are generic over a route or a set of routes, so pass typeof route to type a single wrapper method and typeof routes to type a whole surface.

On this page