npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

post-they

v0.1.5

Published

Write Postman collections as code. Full IntelliSense, imports/exports, auto-looping, TypeScript support. Compile and run API tests from the terminal.

Downloads

648

Readme

post-they

Write Postman collections as code. Get full IntelliSense in VS Code, use imports/exports, loop over data without boilerplate — then compile and run your API tests directly from the terminal.

No Postman GUI needed. The output is a standard collection.json that runs anywhere — in post-they, Newman, or Postman itself.

Why?

Postman is great for exploring APIs, but once you need version control, code reuse, and a proper dev workflow it gets in the way. post-they lets you:

  • Write requests and test scripts as regular JavaScript files
  • Use import/export for shared helpers and test data
  • Get full autocomplete for the pm API (variables, request, response, assertions)
  • Loop over test data with zero boilerplate
  • Compile to a standard Postman collection that runs anywhere Newman does
  • Import existing Postman collections and keep working in code
  • Work in TypeScript instead of JavaScript if you want to

Install

As a project devDependency (recommended):

npm install --save-dev post-they

Then add scripts to your package.json:

{
  "scripts": {
    "test": "post-they run",
    "build": "post-they build"
  }
}

Now npm test compiles and runs your collection.

Or install globally for quick access to post-they init and one-off usage:

npm install -g post-they

Quick start

# Create a new project (scaffolds src/ + a full example in src-example/)
npx post-they init

# Try the built-in example (starts a test server, runs full CRUD tests)
npx post-they example

# Write your own requests in src/requests/, then run:
npx post-they run

# Import an existing Postman collection
npx post-they import my-collection.json

Project structure

src/
  collection.js              # Collection name, request order, collection-level scripts
  data/
    pets.json                # Test data (plain JSON)
  helpers/
    validate.js              # Shared helper functions
  requests/
    get-all-pets.js          # One file per request
    create-pets.js
    read-pets.js

Defining requests

Each request is a JavaScript file. The default export is the request definition, and named exports handle scripts and data.

export default {
  method: 'GET',
  url: '{{baseUrl}}/pets'
};

export function postResponse() {
  const pets = pm.response.json();
  pm.test('Status code is 200', () => pm.response.to.have.status(200));
  pm.test('Response is an array', () => pm.expect(pets).to.be.an('array'));
}

Available exports

| Export | Type | Description | |--------|------|-------------| | default | object | The request definition (method, url, body, headers) | | data | array | Test data to loop over (see Looping over data) | | preRequest | function | Runs before the request is sent | | postResponse | function | Runs after the response is received |

The pm object

Inside preRequest and postResponse functions you have access to the full Postman sandbox API via the global pm object — with complete IntelliSense in VS Code.

pm.variables.get('key')              // Get a variable
pm.variables.set('key', value)       // Set a variable
pm.response.json()                   // Parse response body as JSON
pm.response.to.have.status(200)      // Assert status code
pm.test('name', () => { ... })       // Named test assertion
pm.expect(value).to.equal(expected)  // Chai-style assertion
pm.sendRequest(url, callback)        // Send additional requests
pm.info.requestName                  // Current request name
pm.execution.setNextRequest(name)    // Control execution flow

Looping over data

Export a data array and your request will automatically loop over each item. The current item is passed as a parameter to preRequest and postResponse — no counters, no manual looping.

import pets from '../data/pets.json' with { type: 'json' };

export { pets as data };

export default {
  method: 'POST',
  url: '{{baseUrl}}/pets',
  body: {
    name: '{{petName}}',
    species: '{{petSpecies}}'
  }
};

export function preRequest(pet) {
  pm.variables.set('petName', pet.name);
  pm.variables.set('petSpecies', pet.species);
}

export function postResponse(pet) {
  pm.test('Status 200', () => pm.response.to.have.status(200));

  const result = pm.response.json();
  pet.id = result.lastInsertRowid; // Store for later requests
}

The compiler handles all the counter management and setNextRequest logic behind the scenes.

Reusing requests and test flows

The same request can appear multiple times in your collection order. This is useful for verifying data at different stages — create, verify, update, verify again, delete:

export const order = [
  getAllPets,
  createPets,
  readPets,      // verify after create
  updatePets,
  readPets,      // verify after update — same request, no duplication
  deletePets
];

The compiler generates a single item in the collection and uses a route map to navigate correctly between phases. No code duplication.

Design your dummy data for real testing

Since looping is free, put effort into your test data instead of your test plumbing. Write dummy data that challenges your API — test edge cases like string truncation, special characters, type coercion, empty values, and boundary conditions:

[
  { "name": "O'Malley", "species": "cat" },
  { "name": "", "species": "unknown" },
  { "name": "A very long pet name that might exceed your database column limit", "species": "dog" },
  { "name": "Röbert 🐕", "species": "dog" },
  { "name": "42", "species": "fish" }
]

Every item in the array becomes a full request cycle — POST, GET, PUT, DELETE — with zero extra code. The loop does the work, you focus on the data.

Shared helpers

Put reusable functions in helpers/ and import them in your request files. The compiler converts them to Postman's eval pattern automatically.

// helpers/validate.js
export function validatePet(pet) {
  pm.expect(pet.name).to.be.a('string');
  pm.expect(pet.species).to.be.a('string');
}
// requests/read-pets.js
import { validatePet } from '../helpers/validate.js';

export function postResponse(pet) {
  const petFromDb = pm.response.json();
  pm.test('Pet has valid fields', () => validatePet(petFromDb));
}

Helpers are only included in the scripts that actually use them.

Collection configuration

collection.js defines the collection name, request order, and optional collection-level scripts.

import getAllPets from './requests/get-all-pets.js';
import createPets from './requests/create-pets.js';
import readPets from './requests/read-pets.js';

export const name = 'PetTest';
export const order = [getAllPets, createPets, readPets];

The order array determines execution order. If omitted, import order is used.

You can also add collection-level scripts that run before/after every request:

export const name = 'PetTest';

export function preRequest() {
  pm.variables.set('baseUrl', 'http://localhost:4117');
}

TypeScript support

post-they supports TypeScript out of the box. Write your source files as .ts — the compiler strips types automatically using esbuild before building the collection. Postman's sandbox runs plain JavaScript, so types exist only at authoring time.

// types.ts
export interface Pet {
  name: string;
  species: string;
  id?: string;
}
// requests/create-pets.ts
import type { Pet } from '../types.js';
import pets from '../data/pets.json' with { type: 'json' };

export { pets as data };

export default {
  method: 'POST',
  url: '{{baseUrl}}/pets',
  body: { name: '{{petName}}', species: '{{petSpecies}}' }
};

export function preRequest(pet: Pet): void {
  pm.variables.set('petName', pet.name);
  pm.variables.set('petSpecies', pet.species);
}

Add a tsconfig.json in your source folder to get IntelliSense for the pm global:

{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "lib": ["ESNext"],
    "resolveJsonModule": true
  },
  "include": ["**/*.ts", "../node_modules/post-they/lib/**/*.d.ts"]
}

Note: use import type for type-only imports — they get stripped cleanly and don't generate any runtime code.

Importing existing collections

Convert a Postman collection to post-they source files:

post-they import my-collection.json

This creates a faithful 1:1 conversion of your collection. The original scripts are preserved as-is — you can then refactor to use post-they features like data loops and helper imports at your own pace.

Try it

When you run post-they init, a full working CRUD example is placed in src-example/ alongside your project. To run it:

npx post-they example

This starts a local json-server, compiles the example, runs 242 assertions across a full create-read-update-read-delete cycle with 20 pets, and shuts down the server. Browse src-example/ to see how it's written.

CLI reference

| Command | Description | |---------|-------------| | post-they init [--ts] | Create a new project with example | | post-they build [src-dir] | Compile src/ to collection.json | | post-they build -o out.json | Compile to a specific output file | | post-they run [src-dir] | Compile and run tests | | post-they run --bail | Stop on first test failure | | post-they import <file> | Import a Postman collection to src/ | | post-they example | Run the full CRUD example | | post-they serve | Start json-server for testing | | post-they reset-db | Reset db.json to fresh state |

How it works

post-they is a compiler. Your source files are never executed directly — they're parsed and transformed into a standard Postman collection.json file.

| Source | Compiles to | |--------|-------------| | export default { method, url, body } | item.request | | export function preRequest() {} | event[listen=prerequest] | | export function postResponse() {} | event[listen=test] | | export { data } | Counter + setNextRequest loop | | import { fn } from './helpers/...' | eval(pm.variables.get(...)) pattern | | import data from './data/....json' | pm.variables.set(...) in collection pre-request |

The output is a standard collection that runs in Newman, Postman, or anything else that supports the Postman Collection v2.1 format.

License

MIT