API Reference

defineConfig

Assemble everything one API is made of, and get back the api you mount.

defineConfig({ adapter, routes, identities, ... }) is where an API comes together. It takes what you declared with k, resolves each route's auth, checks the pieces against one another, and hands back the api you mount.

It lives in kizuna.config.ts at the root of your app, which is where the CLI looks for it.

kizuna.config.ts
import { defineConfig } from 'kizunajs';
import { expressAdapter } from '@kizunajs/express';
import { routes } from './src/routes';
import { user } from './src/identities';

export default defineConfig({
    adapter: expressAdapter(),
    routes,
    auth: {
        identities: {
            user,
        },
    },
});
src/index.ts
import express from 'express';
import kizuna from '../kizuna.config';

const app = express();
app.use(express.json());

kizuna.api.mount(app);

What it takes

FieldWhat it is
adapterThe framework this API is served on, as a call: expressAdapter(). Its request reaches every handler, typed.
routesThe route groups k.routes returned. Each route carries its own handler. Omit it while setting up, before there is a route to name.
authWho may call this API: identities, each declared with k.identity and carrying its own guard, and the guardSchema their deny() produces.
requestContextWhat every route resolves before its guards run, declared with k.requestContext.
validationHow a request is checked: issueCodes, the code values k.issue may emit beyond Zod's own.
jobsScheduled work, declared with k.jobs.
jobRunnerHow this deployment runs them: path, method, transport, onError. See Jobs.
pluginsWhat this API installs beside its own routes, as a list.
tagsThe OpenAPI tags routes are grouped under, from k.tags.
typescriptWhere kizuna generate writes the Config, as { outputFile }.
clientsWhat kizuna generate writes from this API.

jobs is what the jobs are, and jobRunner is how this deployment runs them: the first is shared by every config that serves these routes, the second differs between dev and production.

What it hands back

The api: everything you declared, plus the ability to serve it. It carries routes, securitySchemes, tags and the rest, so anything that reads a declaration takes it directly:

scripts/generate-openapi.ts
import { generateOpenApi } from '@kizunajs/openapi';
import kizuna from '../kizuna.config';

const document = generateOpenApi(kizuna.api);

And clients, which the CLI reads when it generates.

Access control

Every route carries its own auth: the identity it requires, and the roles it accepts or the permissions the caller has to hold. Once a config declares an identity, a route without an auth does not compile, so public takes an explicit false. See Access Control for the walkthrough.

src/routes/workspace.ts
export const workspaceRoutes = k.routes('workspace', {
    getWorkspace: k
        .route({
            method: 'GET',
            path: '/workspace',
            auth: 'member',
            responses: {
                200: WorkspaceSchema,
            },
        })
        .handler(({ auth }) => ({
            status: 200,
            body: db.workspaces.find(auth.member.workspaceId),
        })),
});

defineConfig resolves each auth onto that route's security, roles and requires, which the guards, the route handler types, and the OpenAPI document all read.

An identity a route names has to carry a guard, or the config refuses to assemble.

Jobs

Jobs declared with k.jobs go under jobs, beside routes:

kizuna.config.ts
export default defineConfig({
    adapter: expressAdapter(),
    routes,
    jobs,
});

A job carries its own identity, so it declares no auth, and it stays out of api.routes, the OpenAPI document, and the generated Swift, Kotlin and MCP surfaces. See Jobs.

Plugins

Plugins go under plugins, as a list. Each carries the slug your handlers read it under:

kizuna.config.ts
export default defineConfig({
    adapter: expressAdapter(),
    routes,
    plugins: [
        mcpPlugin({
            name: 'My API',
        }),
        openApiPlugin({
            info: {
                title: 'My API',
                version: '1.0.0',
            },
        }),
    ],
});

Their routes are served by api.mount and stay out of api.routes, so the client and the generators do not see them. See Create a Plugin.

On this page