End-to-End Walkthrough

This is the short version of the full Typeweaver loop:

  1. write a spec
  2. generate code
  3. implement one server handler
  4. call it with the generated client

1. Write the spec

Create api/spec/index.ts:

import {
  defineOperation,
  defineResponse,
  defineSpec,
  HttpMethod,
  HttpStatusCode,
} from "@rexeus/typeweaver-core";
import { z } from "zod";

const todoSchema = z.object({
  id: z.string(),
  title: z.string(),
  completed: z.boolean(),
});

const GetTodoDefinition = defineOperation({
  operationId: "GetTodo",
  method: HttpMethod.GET,
  summary: "Get a single todo by ID",
  path: "/todos/:todoId",
  request: {
    param: z.object({
      todoId: z.string(),
    }),
  },
  responses: [
    defineResponse({
      name: "GetTodoSuccess",
      statusCode: HttpStatusCode.OK,
      description: "Todo retrieved successfully",
      body: todoSchema,
    }),
  ],
});

export const spec = defineSpec({
  resources: {
    todo: {
      operations: [GetTodoDefinition],
    },
  },
});

2. Generate code

npx typeweaver generate --input ./api/spec/index.ts --output ./api/generated --plugins clients,server

3. Implement one server handler and start the server

Create server.ts:

import {
  TodoRouter,
  TypeweaverApp,
  createGetTodoSuccessResponse,
} from "./api/generated";

const todoRouter = new TodoRouter({
  requestHandlers: {
    async handleGetTodoRequest(request) {
      return createGetTodoSuccessResponse({
        body: {
          id: request.param.todoId,
          title: "Ship docs",
          completed: false,
        },
      });
    },
  },
});

const app = new TypeweaverApp();

app.route("/api", todoRouter);

Now start the server. TypeweaverApp exposes a standard fetch handler, so it works natively in Fetch API runtimes:

// Deno
Deno.serve({ port: 3000 }, app.fetch);

// Bun
Bun.serve({ port: 3000, fetch: app.fetch });

For Node.js, use the generated nodeAdapter:

import { createServer } from "node:http";
import { nodeAdapter } from "./api/generated/lib/server";

createServer(nodeAdapter(app)).listen(3000);

4. Call it with the generated client

import { GetTodoRequestCommand, TodoClient } from "./api/generated";

const client = new TodoClient({
  baseUrl: "http://localhost:3000/api",
});

const response = await client.send(
  new GetTodoRequestCommand({
    param: {
      todoId: "todo_123",
    },
  }),
);

if (response.type === "GetTodoSuccess") {
  console.log(response.body.title); // "Ship docs"
}

What this proves

One spec now drives:

  • the request and response types
  • the runtime validators
  • the server handler shape
  • the generated client call

That is the core Typeweaver workflow. From here, go deeper with Generate and Run, Clients, or Server Plugin.

Was this page helpful?