Express → Postman collection

Express has no route table you can export and no built-in schema, so most guides start with swagger-jsdoc and a page of YAML comments. routeman-cli reads your routers and handlers directly and writes a full Postman collection in one command, without starting the server.

$ npx routeman-cli

What routeman-cli reads from an Express app

Example

A small shop API: three routers mounted under /api/v1, a JWT middleware, zod schemas on some routes and plain req.body on others.

// src/server.js
const app = express();
app.use(express.json());
app.use('/api/v1/auth', authRouter);
app.use('/api/v1/products', productsRouter);
app.use('/api/v1/orders', ordersRouter);
app.listen(process.env.PORT || 3000);          // .env has PORT=4000

// src/middleware/auth.js
export function requireAuth(req, res, next) {
  const token = (req.headers.authorization || '').replace('Bearer ', '');
  req.user = jwt.verify(token, process.env.JWT_SECRET);
  next();
}

// src/routes/auth.js
router.post('/login', async (req, res) => {
  const { email, password } = req.body;
  const user = await findUser(email, password);
  res.json({ access_token: jwt.sign({ sub: user.id }, process.env.JWT_SECRET) });
});

// src/routes/products.js
const productSchema = z.object({
  name: z.string().min(1).max(120),
  price: z.number().positive(),
  sku: z.string().regex(/^[A-Z]{3}-\d{4}$/),
  category: z.enum(['books', 'electronics', 'clothing']),
  stock: z.number().int().min(0).default(0),
});

router.get('/', async (req, res) => {
  const { page = 1, search, category } = req.query;
  ...
});
router.post('/', requireAuth, async (req, res) => {
  const data = productSchema.parse(req.body);
  ...
});
router.post('/:productId/image', requireAuth, upload.single('image'), ...);

// src/routes/orders.js
router.use(requireAuth);
router.post('/', async (req, res) => {
  const { productId, quantity, couponCode } = req.body;
  ...
});
$ npx routeman-cli
✓ express: 12 requests (5 POST, 4 GET, 1 PUT, 1 DELETE, 1 PATCH)
✓ auth: bearer (login: POST /api/v1/auth/login)
✓ wrote postman/shop-api.postman_collection.json
✓ wrote postman/shop-api.local.postman_environment.json
  done in 0.08s - import the files in Postman (File → Import)

$ npx routeman-cli routes
POST    /api/v1/auth/login                    json: email, password
POST    /api/v1/auth/register                 json: email, password, name
GET     /api/v1/orders                      🔒
POST    /api/v1/orders                      🔒 json: productId, quantity, couponCode
PATCH   /api/v1/orders/{orderId}/cancel     🔒
GET     /api/v1/products
POST    /api/v1/products                    🔒 json: name, price, sku, category, stock
DELETE  /api/v1/products/{productId}        🔒
GET     /api/v1/products/{productId}
PUT     /api/v1/products/{productId}        🔒 json: name, price, sku, category, stock
POST    /api/v1/products/{productId}/image  🔒 form: image
GET     /health
12 routes, auth: bearer (login: POST /api/v1/auth/login)

This is real output from routeman-cli 0.1.0. In Postman:

Request names and descriptions

Requests are named from the method and the resource: List products, Get product, Create product. If your handlers are named functions with a JSDoc comment, the comment's first line becomes the request name:

/**
 * List all widgets
 */
function listWidgets(req, res) { ... }

app.get('/widgets', listWidgets);     // → "List all widgets"

Every description holds a table of body and query fields (type, required, notes) and the source location, such as src/routes/orders.js:8, so you can jump from Postman back to the handler.

TypeScript, monorepos and custom entry files

TypeScript is parsed directly, so you don't need a build step. routeman-cli finds the entry file from your package.json main field and scripts. It resolves tsconfig paths and package.json imports too. If it starts from the wrong file, pass --entry src/server.ts (repeatable), or point at a workspace package with -C apps/api.

If a route is missing, run npx routeman-cli routes and read the warnings. Usually the cause is a path built at runtime from data routeman-cli can't see, such as a value from the database.

Already have swagger-jsdoc?

You can keep it. To build the collection from the spec instead of the code, run npx routeman-cli --openapi ./openapi.json (or a URL). You still get the login script, environments and smoke tests. Most teams get a fuller result from the code, though, because hand-written JSDoc YAML tends to fall behind the handlers.

Full walkthrough: Express API to Postman collection without Swagger.

Read the Node.js docs