pyreon

kubb assembles a generator from plugins; Lathe ships the same outputs as named plugins in one config. lathe init reads kubb.config.ts— its plugin CALLS included, without running them — and this page covers the code that uses the result.

The examples use the Bookshelf example's API. Every Lathe block is typechecked against that generated client in CI; the kubb blocks are illustrative.

1. Run lathe init

npx lathe init
kubbLathe
root + input.pathinput
root + output.pathoutput
output.cleanbuilt in — files Lathe stops generating are removed
pluginOas, pluginTsbuilt in / plugins: ['schemas']
pluginClient({ client: 'axios' | 'fetch', baseURL })client, baseUrl (without an explicit client, Lathe uses pyreon rather than kubb's axios default)
pluginReactQuery (vue/svelte/solid, pluginSwr)plugins: ['queries']
pluginZodvalidator: 'zod'
pluginFakerplugins: ['faker']
pluginMswplugins: ['mocks']
pluginRedocplugins: ['docs']

Plugin options Lathe has no counterpart for (dataReturnType, suspense, custom transformers) are listed by name. A defineConfig(() => ({ … }))function is read too.

2. Client functions and hooks

// kubb
import { getBook } from './gen/clients/axios/getBook'
import { useGetBook } from './gen/hooks/useGetBook'

const { data } = await getBook('1')
const query = useGetBook('1')

Lathe takes one arguments object shaped like the request (params, query,headers, the body) rather than positional path parameters, so adding a query parameter to the spec never shifts an argument.

// @check
import { getBook, useGetBook, useListBooks } from './gen'

const book = await getBook({ params: { bookId: '1' } })
book.title

const query = useGetBook(() => ({ params: { bookId: '1' } }))
query.data()?.title
useListBooks(() => ({ staleTime: 30_000 })).data()

3. Mutations

// @check
import { useCreateBook } from './gen'

const create = useCreateBook({ onError: (e) => console.error(e) })
create.mutate({ json: { title: 'Dune', pages: 412 } })

4. zod

With validator: 'zod' the generated schemas are z.*; they are exported under the model names (Book, NewBook) next to their types, soBook.safeParse(value) works as it did with pluginZod.

5. Faker and MSW

// kubb
import { createBook } from './gen/mocks/createBook'
import { handlers } from './gen/handlers'
setupServer(...handlers).listen()
// @check
import { createBook, installMocks, seedFaker } from './gen/dev'

seedFaker(42)
const book = createBook({ title: 'Pinned title' })
installMocks()
book.id

The factories produce data the generated schemas accept (lengths, ranges, patterns and enums are honoured). The mocks are middleware on the client — nothing to start or stop.

6. Auth and base URL

kubb's generated axios client reads a shared instance you configure. Lathe's equivalent is configureApi, read on every request:

// @check
import { configureApi } from './gen'

let session: string | undefined
configureApi({
  baseUrl: 'https://bookshelf.test/v1',
  headers: () => (session ? { Authorization: `Bearer ${session}` } : {}),
})
session = 'abc'

Keeping axios is one line: client: 'axios'. The generated client.ts then exports the axios instance for your own interceptors.

See also: Lathe, coming from orval,hey-api, openapi-fetch.

Lathe — coming from kubb