Free & open source — no account required

v1.2.5-PRICING-19
Web & Frontend • Engineering Documentation

Postman Mastery: Automating Collection Generation

This technical guide provides an in-depth analysis of the json to postman collection engine, best practices for implementation, and data security standards.

JSON to Postman Collection: Collection v2.1 Format, Pre-request Scripts, Test Assertions, and Newman CI

A Postman Collection file is itself JSON in the Collection v2.1 format — a structured document describing folders, requests, pre-request scripts, and test scripts. Understanding the format lets you generate collections programmatically from OpenAPI specs, API documentation, or request logs rather than building them manually in the UI. The real power comes from pre-request scripts (JavaScript that runs before each request to set up auth tokens, timestamps, or signatures) and test scripts (JavaScript that validates response shape, status codes, and values). This guide covers the Collection v2.1 structure, auth token extraction scripts, Zod-style response validation in Postman's sandbox, and Newman for CI/CD.

Collection v2.1 Format: Complete Structure

{
  "info": {
    "name":    "Product API",
    "schema":  "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "version": "1.0.0"
  },
  "variable": [
    { "key": "baseUrl",  "value": "https://api.example.com/v2" },
    { "key": "apiKey",   "value": "{{$env.API_KEY}}" }
  ],
  "auth": {
    "type":   "bearer",
    "bearer": [{ "key": "token", "value": "{{accessToken}}", "type": "string" }]
  },
  "item": [
    {
      "name": "Authentication",
      "item": [
        {
          "name":    "POST Login",
          "request": {
            "method": "POST",
            "url": {
              "raw":      "{{baseUrl}}/auth/login",
              "host":     ["{{baseUrl}}"],
              "path":     ["auth", "login"]
            },
            "header": [
              { "key": "Content-Type", "value": "application/json" }
            ],
            "body": {
              "mode": "raw",
              "raw":  "{\"email\": \"{{userEmail}}\", \"password\": \"{{userPassword}}\"}"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status 200', () => pm.response.to.have.status(200));",
                  "const body = pm.response.json();",
                  "pm.test('Has access token', () => pm.expect(body.access_token).to.be.a('string'));",
                  "pm.collectionVariables.set('accessToken', body.access_token);",
                  "pm.collectionVariables.set('refreshToken', body.refresh_token);"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}

Pre-request Scripts: Auth Token Management

// Pre-request script: refresh expired access token automatically
// Set this on the collection-level to run before every request

const tokenExpiry = pm.collectionVariables.get('tokenExpiry');
const now         = Date.now();

// Token already valid — skip refresh
if (tokenExpiry && parseInt(tokenExpiry) > now + 60_000) {
  return;  // 60s buffer before expiry
}

// Token expired or missing — fetch a new one
const refreshToken = pm.collectionVariables.get('refreshToken');
if (!refreshToken) return;  // no refresh token — user must login manually

const request = {
  url:    pm.collectionVariables.get('baseUrl') + '/auth/refresh',
  method: 'POST',
  header: [{ key: 'Content-Type', value: 'application/json' }],
  body: {
    mode: 'raw',
    raw:  JSON.stringify({ refresh_token: refreshToken }),
  },
};

pm.sendRequest(request, (err, response) => {
  if (err) { console.error('Token refresh failed:', err); return; }
  if (response.code !== 200) { console.error('Refresh error:', response.text()); return; }

  const body = response.json();
  pm.collectionVariables.set('accessToken',  body.access_token);
  pm.collectionVariables.set('refreshToken', body.refresh_token);
  pm.collectionVariables.set('tokenExpiry',  String(now + body.expires_in * 1000));
});

// Pre-request for HMAC-signed APIs (like Stripe/Shopify webhook verification)
const crypto   = require('crypto-js');
const apiKey   = pm.environment.get('apiKey');
const apiSecret = pm.environment.get('apiSecret');
const timestamp = Math.floor(Date.now() / 1000).toString();

const signature = crypto.HmacSHA256(timestamp + '.' + pm.request.body, apiSecret).toString();
pm.request.headers.add({ key: 'X-Timestamp',  value: timestamp });
pm.request.headers.add({ key: 'X-Signature',  value: 'sha256=' + signature });

Test Scripts: Comprehensive Response Validation

// Test scripts run after the response is received
// pm.test() groups assertions; failing tests don't stop execution

// ── Status and headers ───────────────────────────────────────
pm.test('Status 201 Created', () =>
  pm.response.to.have.status(201)
);

pm.test('Content-Type is JSON', () =>
  pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json')
);

pm.test('Has Location header', () =>
  pm.expect(pm.response.headers.get('Location')).to.match(/\/products\/[a-z0-9-]+$/)
);

pm.test('Response under 500ms', () =>
  pm.expect(pm.response.responseTime).to.be.below(500)
);

// ── Body shape validation ─────────────────────────────────────
const body = pm.response.json();

pm.test('Response has required fields', () => {
  pm.expect(body).to.have.property('id').that.is.a('string');
  pm.expect(body).to.have.property('name').that.is.a('string').and.not.empty;
  pm.expect(body).to.have.property('price_cents').that.is.a('number').and.above(0);
  pm.expect(body).to.have.property('created_at').that.matches(/^\d{4}-\d{2}-\d{2}T/);
});

pm.test('ID format is UUID', () =>
  pm.expect(body.id).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
);

// ── Chaining requests: save IDs for use in subsequent requests ─
pm.collectionVariables.set('createdProductId', body.id);

// ── TV4 JSON Schema validation (built into Postman sandbox) ────
const productSchema = {
  type: 'object',
  required: ['id', 'name', 'price_cents', 'in_stock'],
  properties: {
    id:          { type: 'string' },
    name:        { type: 'string' },
    price_cents: { type: 'integer', minimum: 0 },
    in_stock:    { type: 'boolean' },
    created_at:  { type: 'string' },
  },
  additionalProperties: true,
};

pm.test('Response matches schema', () =>
  pm.expect(tv4.validate(body, productSchema)).to.be.true
);

Programmatic Collection Generation from OpenAPI

// Generate a Postman collection from an OpenAPI spec
// npm install openapi-to-postmanv2

import { convert } from 'openapi-to-postmanv2';
import { readFileSync, writeFileSync } from 'fs';
import yaml from 'js-yaml';

const spec = yaml.load(readFileSync('./openapi.yaml', 'utf-8'));

convert({ type: 'json', data: spec }, {
  requestParametersResolution: 'Example',
  folderStrategy:    'Tags',          // group requests by OpenAPI tags
  includeAuthInfoInExample: false,    // don't embed credentials in examples
  optimizeConversion: false,
  enableOptionalParameters: true,
  keepImplicitHeaders: false,
}, (err, conversionResult) => {
  if (!conversionResult.result) {
    throw new Error('Conversion failed: ' + conversionResult.reason);
  }

  const collection = conversionResult.output[0].data;

  // Post-process: add pre-request scripts and test scripts
  collection.event = [
    {
      listen: 'prerequest',
      script: { type: 'text/javascript', exec: [TOKEN_REFRESH_SCRIPT] },
    },
  ];

  writeFileSync('./postman/collection.json', JSON.stringify(collection, null, 2));
  console.log(`Generated ${collection.item.length} folders`);
});

Newman: Running Collections in CI/CD

// Newman runs Postman collections from the command line
// npm install -g newman newman-reporter-htmlextra

// Basic run against staging environment
// newman run collection.json \
//   --environment staging.json \
//   --reporters cli,json \
//   --reporter-json-export results/newman-report.json

// With HTML report
// newman run collection.json \
//   --environment staging.json \
//   --reporters htmlextra \
//   --reporter-htmlextra-export results/index.html

// GitHub Actions workflow
name: API Integration Tests
on: [push, pull_request]
jobs:
  api-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm install -g newman newman-reporter-htmlextra
      - run: |
          newman run postman/collection.json \
            --environment postman/staging.json \
            --env-var "API_KEY=${{ secrets.STAGING_API_KEY }}" \
            --reporters cli,htmlextra \
            --reporter-htmlextra-export results/index.html \
            --bail                    # stop on first failure
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: newman-results
          path: results/

// Environment file (postman/staging.json)
{
  "name": "Staging",
  "values": [
    { "key": "baseUrl",       "value": "https://staging.api.example.com/v2", "enabled": true },
    { "key": "userEmail",     "value": "test@example.com",                   "enabled": true },
    { "key": "userPassword",  "value": "{{$env.TEST_PASSWORD}}",             "enabled": true }
  ]
}

Best Practices for Production

  • Store access tokens in collection variables, not environment variables: Collection variables persist only for the duration of a collection run, which is the right scope for auth tokens. Environment variables persist across runs and can leak tokens between test sessions. Set accessToken as a collection variable in the login test script and read it in the auth bearer token config.
  • Add response time assertions to every request: pm.expect(pm.response.responseTime).to.be.below(500) turns performance regressions into test failures. Without explicit timing tests, slow endpoints go unnoticed until users complain. Adjust the threshold per endpoint type: 200ms for simple reads, 1000ms for writes, 5000ms for batch operations.
  • Chain requests using collection variables: Set pm.collectionVariables.set('productId', body.id) in a POST test script, then use {{productId}} in subsequent GET/PUT/DELETE requests. This makes your collection self-contained — no manual ID substitution between test runs.
  • Generate collections from OpenAPI specs, don't maintain both by hand: Manually keeping an OpenAPI spec and a Postman collection in sync is a maintenance burden. Generate the collection from the spec using openapi-to-postmanv2 and add custom test scripts on top. The OpenAPI spec is the source of truth; the collection is derived.

FAQ

Q: What's the difference between Postman collection variables, environment variables, and global variables?
A: Collection variables are scoped to one collection run — reset each time. Environment variables persist across runs and are shared between collections in the same environment. Global variables are visible to all collections in all environments. Use collection variables for session state (tokens, created IDs), environment variables for configuration (base URLs, credentials), and avoid global variables unless absolutely necessary.

Q: Can I run Postman collections in parallel?
A: Newman runs requests sequentially within a collection by default. For parallel execution across multiple collections, run multiple Newman processes simultaneously. Postman's cloud runner supports parallelism, but Newman CLI does not natively. If you need parallel API testing with more sophisticated orchestration, consider k6 or Artillery instead.

Q: How do I test OAuth2 PKCE flows in Postman?
A: Postman supports OAuth2 PKCE natively in the auth configuration — use the "OAuth 2.0" auth type with "PKCE" selected. For scripted flows, use a pre-request script with pm.sendRequest() to get the code verifier/challenge, redirect to the auth URL, and exchange the code for a token. Complex OAuth flows are easier to test with dedicated OAuth test tools alongside Postman for API endpoint testing.

Developer FAQ

Is the processing local-only?

Absolutely. TypeMorph operates entirely within your browser's sandbox. We use Web Workers for high-performance computation without ever transmitting your JSON, SQL, or API data to a remote server.

Can I use this for enterprise projects?

Yes. The tool is designed for professional software engineers who require GDPR compliance and data privacy. It is trusted by developers at top-tier startups and financial institutions.