chowbea-axios

Installation

Install chowbea-axios globally or use it directly with npx.

You need the CLI before you can stop hand-writing API types. This page gets you there — global install, npx, or "I already have Axios and I'm not starting over."

Prerequisites

  • Node.js 20 or higher (tested in CI on 20, 22, 24 across Linux, macOS, and Windows)
  • A project with package.json
  • An OpenAPI specification (v3.x) — endpoint URL or local file

chowbea-axios is ESM only. package.json declares "type": "module", so require("chowbea-axios") from a CommonJS file fails with ERR_REQUIRE_ESM. Use dynamic import() or migrate the importing file to ESM. The CLI binary works regardless of your project's module format.

Installation Options

Install globally to run chowbea-axios from anywhere:

npm install -g chowbea-axios
yarn global add chowbea-axios
pnpm add -g chowbea-axios
bun add -g chowbea-axios

Verify it works:

chowbea-axios --version

Using npx (No Installation)

Run commands directly:

npx chowbea-axios init
npx chowbea-axios fetch
npx chowbea-axios watch

npx downloads the package on first use. Subsequent runs are faster — unlike your manual type definitions, which get slower every sprint.

Dependencies

chowbea-axios installs axios in your project during init. No manual step.

Type generation is built in — no separate codegen packages. The CLI ships its own OpenAPI-to-TypeScript generator and writes files atomically.

Optional: Interactive Dashboard

Running chowbea-axios with no command launches an interactive TUI dashboard for fetch, generate, diff, validate, watch, plugins, and endpoint inspection. Requires Bun. Under Node, the CLI re-launches under Bun automatically; if Bun isn't installed, it falls back to headless mode with a hint. Headless commands (fetch, generate, watch, etc.) work under Node alone — use those in CI. See the dashboard guide.

Local-First Execution

When you have chowbea-axios installed both globally (or via npx) and as a devDependency in your project, the CLI automatically hands off to the project's local copy. This ensures every developer and CI run uses the exact version pinned in your lockfile, not whatever the global install happens to be.

How it works

  1. You run chowbea-axios fetch (global install or npx)
  2. The CLI walks up from the current working directory looking for node_modules/chowbea-axios/package.json
  3. If found, it spawns the project-local version's bin entry and exits with that child's status
  4. If not found (or the spawn fails with an error), it continues with the global/npx version and logs a warning

This happens transparently on every command — no flags, no config. A sentinel environment variable (CHOWBEA_LOCAL_DELEGATED=1) prevents infinite loops if the delegated child somehow tries to delegate again.

Why it matters

  • Reproducible builds — CI and every developer run the same version
  • Safe upgrades — upgrade the local version first, test it, then commit your lockfile
  • No surprises — a global update never breaks a project that pins v2.x

Adding as a devDependency

npm install -D chowbea-axios

Now the global chowbea-axios fetch (or npx chowbea-axios fetch) will use the lockfile-pinned version when run inside this project. In pinned-inputs mode, the workflows' npx chowbea-axios commands resolve the version from node_modules, never the registry — that's how sync PRs stay on the same version as the branch they're updating.

Adding to an Existing Project

Already have Axios wired up with interceptors and battle scars? Fine. chowbea-axios generates an isolated client alongside your existing code. Migrate at your pace.

Initialize chowbea-axios

Run init in your project root:

npx chowbea-axios init

Enter your OpenAPI endpoint URL and choose an output folder (e.g., src/services/api). Init also adds api:* scripts to package.json.

Generate the typed client

Fetch your spec and generate:

npx chowbea-axios fetch

Or, after init:

npm run api:fetch

This creates a typed client in your chosen folder. Your existing Axios code is untouched.

Use both clients side by side

Old calls keep working. Use the generated client for new features or when you're already editing a file:

// Your existing code (still works)
import axios from 'axios';
const user = await axios.get('/api/users/123');

// New typed client (use for new work)
import { api } from '@/services/api';
import type { UserDto } from '@/services/api/_generated/api.contracts';

const { data, error } = await api.op.getUserById({ id: '123' });
// data is UserDto once you've handled error

For app structure beyond raw calls, see The Query Layer.

Migrate at your own pace

No big-bang rewrite required. Replace old Axios calls when you touch that code. Over time, the codebase becomes fully typed without a "API migration" epic on the roadmap.

Using Your Existing Axios Instance

Already have an instance with auth interceptors and custom config? Point the generated client at it.

Open api.instance.ts and swap the export:

// Before: generated instance
import axios from "axios";

export const axiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
  timeout: 30000,
});

// After: your existing instance
import { myAxiosInstance } from '@/lib/axios';

export const axiosInstance = myAxiosInstance;

The typed client uses your instance — interceptors, headers, and config intact.

api.instance.ts is never overwritten after initial creation. Your changes persist across regenerations.

Scripts You'll Use Daily

After init, your package.json includes:

{
  "scripts": {
    "api:fetch": "chowbea-axios fetch",
    "api:generate": "chowbea-axios generate",
    "api:watch": "chowbea-axios watch",
    "api:status": "chowbea-axios status",
    "api:validate": "chowbea-axios validate",
    "api:diff": "chowbea-axios diff"
  }
}

Run watch mode alongside your dev server so types stay in sync:

{
  "scripts": {
    "dev:all": "concurrently \"npm run api:watch\" \"npm run dev\""
  }
}

dev:all keeps the spec warm while you iterate. Highly recommended.

Verify Installation

Check that everything is wired up:

chowbea-axios status

Before your first fetch:

╭────────────────────────────────────────
│ Status
├────────────────────────────────────────
│
│ Config: api.config.toml (created)
│   endpoint: http://localhost:3000/docs/swagger/json
│   output: app/services/api
│
│ Spec:
│   cached: no - run 'chowbea-axios fetch' first
╰────────────────────────────────────────

If you see that, you're one api:fetch away from never writing interface User by hand again.

Next Steps

On this page