Skip to content

kai-nguyen-aligent/bru2openapi

Repository files navigation

bru2openapi

Generate OpenAPI 3.0 specs from Bruno API collections.

bru2openapi takes a Bruno collection directory, runs every request through a capture proxy, and converts the recorded traffic into an OpenAPI specification using mitmproxy2swagger.

How it works

flowchart LR
    A[Bruno Collection] -->|bru run| B[mitmdump proxy]
    B -->|captures traffic| C[flows.mitm]
    C -->|mitmproxy2swagger| D[openapi.yaml]
Loading
  1. Reads the base URL from your Bruno environment file
  2. Starts mitmdump as a capture proxy
  3. Runs all collection requests through the proxy via the bru CLI
  4. Converts captured traffic to HAR format
  5. Generates an OpenAPI spec with mitmproxy2swagger

Installation

Requires Node.js 22+.

npm install -g bru2openapi

Quick start

# Docker mode (default) -- only requires Docker
bru2openapi ./my-collection --env Development --base-url-var BaseUrl

# Local mode -- requires mitmproxy, mitmproxy2swagger, and bru CLI
bru2openapi ./my-collection --env Development --base-url-var BaseUrl --local

If you omit required flags, the CLI will prompt you interactively.

Usage

bru2openapi <collection-dir> [flags]

ARGUMENTS
  collection-dir            Path to Bruno collection directory

FLAGS
  -e, --env <name>          Bruno environment name
  -b, --base-url-var <name> Name of the env variable holding the base URL
      --format json|xml     Expected API response format (default: json)
      --[no-]get-only       Only run GET requests (default: true)
      --include <folders>   Comma-separated folders to include, or ALL (default: ALL)
      --exclude <folders>   Comma-separated folders to exclude
      --out <dir>           Output directory (default: .)
      --local               Run locally instead of Docker
  -y, --yes                 Skip confirmation prompts

Execution modes

Docker mode (default)

Only requires Docker. The CLI builds and caches a Docker image (bru2openapi:<version>) containing mitmproxy, mitmproxy2swagger, and the Bruno CLI. The image is rebuilt automatically when the CLI version changes.

bru2openapi ./collection -e Production -b ApiBaseUrl

Local mode (--local)

Runs the pipeline directly on your machine. You need to install the dependencies yourself:

pip install mitmproxy mitmproxy2swagger
npm i -g @usebruno/cli

Then:

bru2openapi ./collection -e Production -b ApiBaseUrl --local

The CLI checks for all three dependencies at startup and tells you what to install if anything is missing.

Config file

Place a .bru2openapi.yml in your collection root to save per-collection settings:

env: Development
baseUrlVar: BaseUrl
format: xml
getOnly: true
include:
  - Stores
  - Products
forceArrayJPaths:
  - Stores
  - Order.Payments
  - Persons

Resolution order

CLI flags take precedence over the config file, which takes precedence over interactive prompts, which fall back to built-in defaults:

CLI flags > .bru2openapi.yml > interactive prompts > defaults

forceArrayJPaths (XML only)

When format: xml, XML responses are converted to JSON before schema generation. XML-to-JSON conversion can lose array semantics when a collection contains only one element. The forceArrayJPaths list tells the converter which jPaths are always arrays, using dot-separated paths from the document root (e.g. Order.Payments).

Array jPaths are also auto-discovered via two heuristics:

  • Parent element has @Type="Array" attribute
  • Multiple same-name sibling elements exist in the raw XML

Folder filtering

--include

Limit which collection folders are run. Accepts a comma-separated list or the keyword ALL:

# Only run Stores and Products folders
bru2openapi ./collection -e Dev -b BaseUrl --include Stores,Products

# Run all folders (override a restrictive config file)
bru2openapi ./collection -e Dev -b BaseUrl --include ALL

ALL cannot be combined with specific folder names (e.g. --include ALL,Stores is an error).

--exclude

Skip specific folders:

bru2openapi ./collection -e Dev -b BaseUrl --exclude Returns,Coupons

--include and --exclude are mutually exclusive.

Interactive prompts

When run in a terminal without all required flags, the CLI prompts for missing values with defaults pre-filled from the config file:

? Bruno environment (Development):
? Base URL variable (BaseUrl):
? Response format (json):
? GET requests only (Y/n):
? Include folders (ALL):
? Output directory (.):
? Run locally (no Docker) (y/N):

Press Enter to accept the default or type a new value.

Use --yes / -y to skip all prompts (for CI/scripts). If required values are still missing, the CLI exits with an error.

Output

The CLI produces these files in the output directory:

File Description
<collection-name>-openapi.yml The generated OpenAPI spec
flows.mitm Raw mitmproxy capture file
flows.har HAR file (converted from flows)
requests-report.json Execution log with failures and array jPath info

Post-generation

The generated spec is a starting point. Consider these improvements:

  1. Add descriptions to paths and parameters
  2. Add tags to group endpoints
  3. Add security schemes (e.g. Basic Auth)
  4. Parameterise path variables (replace hardcoded IDs with {paramName})
  5. Add error responses (400, 401, 404, 500)
  6. Validate: npx @redocly/cli lint <spec-file>

Development

pnpm install
pnpm test

License

ISC

About

Generate OpenAPI 3.0 specs from [Bruno](https://www.usebruno.com/) API collection

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors