Skip to main content
Kweri supports two usage patterns. Choose the one that fits your project:
Path A — With an OpenAPI specPath B — Without an OpenAPI spec
EndpointsGenerated by kweri-genDefined manually with defineEndpoint
HooksuseGet, usePost, usePut, usePatch, useDeleteuseQuery, useMutation
Best forTeams with a Swagger / OpenAPI specTeams hand-crafting their API layer

1. Install

npm install kweri
# or
bun add kweri

2. Create a Kweri instance

// src/lib/kweri.ts
import { Kweri } from 'kweri'

export const kweri = new Kweri({
  baseURL: 'https://api.example.com',
  staleTime: 30_000,
  cacheTime: 300_000,
  enableDevTools: true
})

3. Generate from your spec

npx kweri-gen https://api.example.com/openapi.json
This writes .generated/client.js with TypeBox schemas and an EndpointByMethod map for every route in your spec. Re-run whenever your API changes.

4. Set up path hooks

// src/hooks/useKweri.ts
import { useSyncExternalStore } from 'react'
import { createReactPathHooks } from 'kweri'
import { EndpointByMethod } from 'kweri/generated'
import { kweri } from '@/lib/kweri'

export const { useGet, usePost, usePut, usePatch, useDelete } =
  createReactPathHooks(useSyncExternalStore, kweri, EndpointByMethod)

export { kweri }
Create the hook factory once and export it. Don’t call createReactPathHooks or createVuePathHooks inside a component.

5. Fetch data in your components

// src/components/UserList.tsx
import { useGet, usePost, kweri } from '@/hooks/useKweri'

export function UserList() {
  const { data, isLoading, isError, error } = useGet('/users', {})

  if (isLoading) return <p>Loading...</p>
  if (isError)   return <p>Error: {error?.message}</p>

  return (
    <ul>
      {data?.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  )
}

export function CreateUserButton() {
  const { mutateAsync, isLoading } = usePost('/users')

  async function handleClick() {
    await mutateAsync({ body: { name: 'Alice' } })
    kweri.invalidateByPath('/users')
  }

  return (
    <button onClick={handleClick} disabled={isLoading}>
      {isLoading ? 'Creating...' : 'Create user'}
    </button>
  )
}

Path B — Without an OpenAPI spec

Use this path when you don’t have a spec and want to define endpoints by hand.

1. Install

npm install kweri
# or
bun add kweri

2. Create a Kweri instance

// src/lib/kweri.ts
import { Kweri } from 'kweri'

export const kweri = new Kweri({
  baseURL: 'https://api.example.com',
  staleTime: 30_000,
  cacheTime: 300_000,
})

3. Define your endpoints

// src/api/users.ts
import { Type, defineEndpoint } from 'kweri'

export const getUsers = defineEndpoint({
  method: 'GET',
  path: '/users',
  params: Type.Object({}),
  response: Type.Array(
    Type.Object({
      id:    Type.Number(),
      name:  Type.String(),
      email: Type.String()
    })
  )
})

export const createUser = defineEndpoint({
  method: 'POST',
  path: '/users',
  params: Type.Object({
    body: Type.Object({ name: Type.String(), email: Type.String() })
  }),
  response: Type.Object({ id: Type.Number(), name: Type.String(), email: Type.String() })
})

4. Set up hooks

// src/hooks/useKweri.ts
import { useSyncExternalStore } from 'react'
import { createReactQueryHooks } from 'kweri'
import { kweri } from '@/lib/kweri'

export const { useQuery, useMutation } =
  createReactQueryHooks(useSyncExternalStore, kweri)

5. Fetch data in your components

// src/components/UserList.tsx
import { useQuery, useMutation, kweri } from '@/hooks/useKweri'
import { getUsers, createUser } from '@/api/users'

export function UserList() {
  const { data, isLoading, isError, error } = useQuery(getUsers, {})

  if (isLoading) return <p>Loading...</p>
  if (isError)   return <p>Error: {error?.message}</p>

  return (
    <ul>
      {data?.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  )
}

export function CreateUserButton() {
  const { mutateAsync, isLoading } = useMutation(createUser)

  async function handleClick() {
    await mutateAsync({ body: { name: 'Alice', email: '[email protected]' } })
    kweri.invalidateByPath('/users')
  }

  return (
    <button onClick={handleClick} disabled={isLoading}>
      {isLoading ? 'Creating...' : 'Create user'}
    </button>
  )
}