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
Maintainers
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/exportfor shared helpers and test data - Get full autocomplete for the
pmAPI (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-theyThen 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-theyQuick 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.jsonProject 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.jsDefining 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 flowLooping 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.jsonThis 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 exampleThis 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
