<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/logo-light.png">
  <source media="(prefers-color-scheme: light)" srcset="assets/logo-dark.png">
  <img alt="DAxTA" src="assets/logo-dark.png" width="120" height="120">
</picture>

# DAxTA

**API Test → API Documentation**

You already wrote the tests.  
Don't document the same thing twice.

![npm](https://img.shields.io/npm/v/@t0.labs/daxta?color=111111&label=npm&logo=npm)![node](https://img.shields.io/node/v/@t0.labs/daxta?color=111111&label=node)![license](https://img.shields.io/npm/l/@t0.labs/daxta?color=111111)

---

DAxTA turns your existing **NestJS API integration tests** into living API documentation.

Your tests already know the requests, responses, status codes, headers, validation failures, authentication scenarios, omitted fields, and edge cases of your API.

DAxTA captures that real traffic while your tests run and turns it into interactive **OpenAPI documentation** on your application at `/api-docs`.

**No duplicate API definitions. No manually maintained examples. No documentation-specific decorators.**

```ts
import { apiDocs } from '@t0.labs/daxta';

apiDocs(app); // NestJS — mounts /docs on dev/test/staging NODE_ENV only
```

Generation happens when Jest finishes (reporter) or when you run `daxta generate`. You do not call `generateApiDocs()` in `main.ts`.

---



## Why DAxTA?

When you build an API, you already describe its behavior in your tests.

Your integration tests know:

- what request is sent
- what response should be returned
- which status code is expected
- which headers are required
- positive scenarios
- negative scenarios
- invalid inputs
- omitted fields
- authentication failures
- edge cases

Then we often define much of the same information **again** for Swagger, Postman, or another API documentation tool.

DAxTA removes that duplication.

```text
Write API
   ↓
Write tests
   ↓
Run tests
   ↓
DAxTA captures real API behavior
   ↓
Interactive /api-docs
   ↓
OpenAPI → Postman / other tools
```

---



## What you get


| From your tests               | In DAxTA                        |
| ----------------------------- | ------------------------------- |
| Real request / response pairs | Interactive `/api-docs` UI      |
| Positive scenarios            | Success examples                |
| Negative scenarios            | Error examples                  |
| Validation failures           | Invalid cases                   |
| Authentication scenarios      | Recorded headers                |
| Omitted / optional fields     | DTO field metadata              |
| Status codes                  | Executable API calls            |
| Multiple test cases           | Multiple examples per operation |
| Recorded API set              | OpenAPI + Postman export        |


Different tests for the same endpoint automatically become different API examples.

```text
POST /v1/users

├── 201  User created
├── 400  Invalid email
├── 400  Missing required field
├── 401  Missing authentication
└── 409  User already exists
```

These examples come from **actual test executions**, not manually maintained documentation.

---



## How it works

```text
  your Jest suite
       │
       │  supertest / superagent
       ▼
  your real NestJS endpoints
       │
       │  DAxTA records traffic
       ▼
  recorded API scenarios
       │
       │  no OpenAPI rebuild mid-run
       ▼
  onRunComplete
       │
       │  one full build
       ▼
  OpenAPI + DAxTA UI
       │
       ▼
  http://localhost:3000/api-docs
```

1. **Install** attaches DAxTA to Jest using `setupFilesAfterEnv` and a reporter.
  Your existing `test:integration` command remains the entrypoint. DAxTA does not wrap your test process.
2. **Run your tests normally.**
  DAxTA records the real HTTP traffic generated by your tests.
3. **When Jest finishes**, DAxTA performs a single documentation build.
4. `apiDocs(app)` mounts the generated documentation on your NestJS application in every environment except production.

---



## What DAxTA covers

DAxTA records **real HTTP traffic** from NestJS API integration tests.

That is the point. Documentation is generated from the same requests your tests already send against the running application — not from controller decorators, and not from unit tests that never hit HTTP.

**Covered** — Nest e2e / integration tests that go through **supertest** or **superagent**:

```ts
request(app.getHttpServer())
  .post('/v1/users')
  .set('authorization', token)
  .send({ email: 'ada@example.com' })
  .expect(201);
```

If Jest is wired (`setupFilesAfterEnv` + reporter), those hits become `/api-docs` when the suite finishes.

**Not covered** — anything that never passes through that HTTP client:


| Test style                                         | Recorded? |
| -------------------------------------------------- | --------- |
| Nest e2e with `request(app.getHttpServer())`       | Yes       |
| Service / unit tests (`TestingModule`, no HTTP)    | No        |
| `axios`, `fetch`, `got`                            | No        |
| Playwright / Cypress                               | No        |
| GraphQL or WebSocket (unless over superagent HTTP) | No        |


If the test does not hit the API over HTTP the way your clients do, DAxTA has nothing to document. That is intentional: the source of truth is **observed API behavior**, not mocked internals.

---



## Install

```bash
pnpm dlx @t0.labs/daxta install
```

or:

```bash
npx @t0.labs/daxta install
```

The installer wires `apiDocs(app)` into your NestJS entrypoint, hooks DAxTA into Jest, and writes `daxta.config.ts`.

Then run your existing integration tests:

```bash
pnpm run test:integration
```

When Jest finishes, your documentation is ready.

Start your application as usual:

```bash
pnpm start:dev
```

Open:

```text
http://localhost:3000/api-docs
```

That's it.

**Your tests are now your API documentation source.**

Flags: `--yes` · `--dry-run` · `--skip-main` · `--skip-dep` · `--main <path>` · `--fast`

---



## Uninstall

```bash
pnpm dlx @t0.labs/daxta uninstall
```

or, if DAxTA is already a dependency:

```bash
pnpm daxta uninstall
```

It unwinds everything the installer put in place: the `apiDocs(app)` call in your NestJS entrypoint, the Jest
reporter and setup hooks, the wrapped test script and any `daxta:*` scripts in `package.json`, `daxta.config.ts`,
the generated `daxta/` output directory, the `.gitignore` entries, and the legacy `DAXTA_DOCS` line if an older
install left one behind. `@t0.labs/daxta` itself is removed with your package manager unless you pass
`--keep-dep`.

Your tests are untouched — they were never DAxTA-specific to begin with.

Preview first if you want to see the plan without writing anything:

```bash
pnpm dlx @t0.labs/daxta uninstall --dry-run
```

Flags: `--yes` · `--dry-run` · `--keep-dep` · `--fast`

---



## Docs UI

DAxTA provides an interactive API workbench directly on your application.

From `/api-docs` you can:

- browse recorded API operations
- switch between scenarios generated by different tests
- inspect real requests and responses
- inspect status codes and headers
- inspect required / optional DTO fields
- send API requests
- copy requests as cURL
- work with different environments and header groups
- select APIs and examples for export

Think of it as an API exploration layer generated from the tests you already wrote.

### Recorded scenarios

Scenarios stay tied to the exact request that produced them — including headers.

For example, an empty authorization header from a `401` test remains empty in that scenario.

Environment tokens only override keys that were actually recorded.

---



## DTO fields

Field metadata is derived from `class-validator` / `class-transformer` DTO metadata together with observed traffic.

```text
email        required
password     required
firstName    optional
lastName     optional
```

This allows DAxTA to understand required and optional fields without another documentation-specific definition of the same contract.

---



## OpenAPI export

DAxTA is not limited to `/api-docs`.

You can select the **APIs and examples** you want, combine them with the appropriate **environment and header groups**, and export using the **OpenAPI** spec plus a **Postman Collection**.

```text
Tests
  ↓
DAxTA
  ↓
Select APIs + Examples
  ↓
Environment + Header Groups
  ↓
OpenAPI / Postman
  ↓
Other tools
```

This also allows you to create customized API sets without exposing the entire `/api-docs` interface from your service.

Your tests remain the source of truth.

**OpenAPI becomes the portable output.**

---



## When `/docs` is mounted

`apiDocs(app)` follows `NODE_ENV`, so the variable your application already sets decides it. There is no
DAxTA-specific flag to manage:

```bash
NODE_ENV=development pnpm start:dev   # /docs mounted
NODE_ENV=dev                           # /docs mounted
NODE_ENV=test                          # /docs mounted
NODE_ENV=staging                       # /docs mounted
NODE_ENV=sta                           # /docs mounted
NODE_ENV=production                    # /docs not mounted
# NODE_ENV unset                       → /docs not mounted
```

The gate is closed by default: only `dev`, `development`, `test`, `sta` and `staging` open the docs. Anything
else — `production`, an unrecognised value, or no value at all — keeps them off, so a deployment that forgets to
set `NODE_ENV` never exposes them. `daxta install` adds `NODE_ENV=development` to your env file only when no env
file declares `NODE_ENV`; an existing value is yours and stays untouched.

Not mounting `/docs` does not remove `@t0.labs/daxta` from your Node image. It only skips the route.

The decision is exported if you need the same answer elsewhere:

```ts
import { docsEnabled } from '@t0.labs/daxta';
```

The path defaults to `/docs`. Override with `DAXTA_DOCS_PATH` or `docsPath` in `daxta.config.ts`.

---



## Commands

```bash
daxta install      # one-shot project setup, including sidebar layout
daxta uninstall    # remove DAxTA wiring from the project
daxta migrate      # upgrade integration after a package bump
daxta generate     # rebuild OpenAPI + UI from recorded traffic
daxta serve        # optional standalone viewer
daxta tree         # reconfigure the /api-docs sidebar
daxta titles       # align test titles with API docs examples
daxta fields …     # export the field map for an operation
daxta call …       # execute an API operation from the CLI
```

`daxta build` is an alias of `daxta generate`.

For most NestJS applications, `apiDocs(app)` is preferred over `daxta serve`.

---



## Sidebar order

```bash
daxta tree
```

controls how API paths are organized inside `/api-docs`.

```text
/v1/admin/baskets

1) URL order
   v1 › admin › baskets

2) Resource-first
   v1 › baskets › admin

3) Custom
   …
```

The selected structure is stored in `daxta.config.ts` as `treeLayout` and `treePathOverrides`.

Then rebuild:

```bash
daxta generate
```

---



## API

**NestJS** — only this belongs in `main.ts`:

```ts
import { apiDocs } from '@t0.labs/daxta';

apiDocs(app);
```

`generateApiDocs()` is not part of the Nest bootstrap. Jest builds the spec after tests; you can also run `daxta generate`.

**Express** (no Nest `app.use` helper):

```ts
import { apiDocsHandler } from '@t0.labs/daxta';

app.use(apiDocsHandler());
```

`apiDocs(app)` works on Express too — it is `app.use(apiDocsHandler())` plus the `NODE_ENV` gate.

**Standalone viewer** (CLI / rare):

```ts
import { serveApiDocs } from '@t0.labs/daxta';

serveApiDocs({ port: 5199 });
```

---



## The idea behind DAxTA

The idea is simple.

If your integration test already proves that:

```text
this request
      ↓
produces this response
      ↓
with this status code
```

then the documentation already exists.

It is just trapped inside your tests.

**DAxTA turns it into something you can explore, execute, export, and share.**

**API Test → API Documentation**

You already wrote the tests. Let DAxTA write the docs.

---



## License

DAxTA is [MIT](LICENSE) licensed.

Copyright (c) 2026 t0.labs