Pre-request and Post-request Scripts in Apifox: A Complete Guide

Overview

Pre-request scripts and post-request scripts are JavaScript code fragments that execute during the API request and response lifecycle. They serve as powerful tools for validating responses, modifying requests dynamically, extracting data, and automating repetitive tasks. By incorporating these scripts into your API testing workflow, you can significantly improve debugging efficiency, ensure接口 correctness, and establish seamless data flow between interconnected APIs.

Pre-request Scripts

Pre-request scripts execute before an API request is sent, enabling dynamic modification of request parameters, headers, authentication tokens, and other request elements. These scripts are essential for scenarios where request data needs to be generated or computed at runtime rather than using static values.

Common use cases for pre-request scripts include:

  1. Dynamic Header Configuration: Setting headers that require runtime-generated values, such as timestamps, nonces, or authorization tokens obtained from authentication endpoints.
  2. Dynamic Parameter Generation: Creating request parameters that change with each execution, including timestamps, random values, signatures computed from request content, and UUIDs.
  3. Authentication Integration: Automatically obtaining access tokens before sending protected requests, handling OAuth flows, and refreshing expired credentials.
  4. Conditional Request Building: Modifying request structure based on environment conditions, feature flags, or other runtime factors.

Variable Substitution

The variable substitution feature processes all referenced variables in request parameters before sending the request. This mechanism is crucial for scenarios involving request signature computation, where parameter values must be replaced with their actual content before cryptographic operations.

Two primary scenarios determine the execution order of variable substitution:

  1. Script-Set Variables: When scripts need to define variibles that will be used in subsequent parameter substitution, these scripts must execute before the substitution phase. Otherwise, the newly created variables won't affect the current request's parameters.
  2. Signature Computation Scripts: When computing digital signatures based on request parameters, scripts must execute after variable substitution to access the actual parameter values rather than template placeholders containing varible references.

Post-request Scripts

Post-request scripts execute after receiving an API response, enabling validation of response content, extraction of data for subsequent requests, and automated testing through assertions. These scripts have access to complete response information including status codes, headers, body content, and response timing metrics.

Key capabilities of post-request scripts include:

  1. Response Validation: Verifying that response status codes, headers, and body content meet expected criteria.
  2. Data Extraction: Parsing response bodies to extract specific values that will be used as input for other API calls in a workflow.
  3. Assertion Testing: Implementing automated tests that validate response characteristics, ensuring APIs behave according to specifications.
  4. Dynamic Variable Population: Storing extracted response data in variables (temporary, environment, or global) for use by downstream requests.

Hierarchy and Inheritance

Both pre-request and post-request scripts support hierarchical configuration through folder-level parent scripts. Parent scripts defined at the folder level are inherited by all APIs within that folder, enabling centralized management of common operations like authentication, variable substitution, and logging.

Individual APIs within a folder can selectively override or disable inherited scripts. When a child API disables script inheritance, the parent-level custom scripts will not execute for that specific API.

When multiple levels of hierarchy exist (global level, folder level, and individual API level), scripts execute in a predictable sequence: global scripts first, followed by folder-level scripts, and finally API-specific scripts. This hierarchical structure ensures consistent behavior across related APIs while maintaining flexibility for API-specific customization.

Variable Extraction and Data Transfer

In API workflows with clear dependencies between requests, extracting data from upstream responses and using it in downstream requests is a common requirement. Consider a scenario where creating a pet record requires using the returned pet ID in subsequent operations for updating or retrieving that record.

The variable extraction feature enables you to capture specific values from API responses and store them in variables for reuse across your project. This approach eliminates manual copying of values and ensures data consistency throughout test sequences.

Specifying Variable Types

Access any API definition in Apifox and navigate to the "Post-request Scripts" section. Add a "Extract Variable" action, selecting the appropriate variable scope: temporary variable, environment variable, or global variable. Environment variables are particularly useful when working across different environments (development, staging, production) as they can be configured per environment.

Passing Data Between APIs

When API B's request parameters depend on data returned from API A, implementing automated data transfer requires a straightforward approach:

  1. API A Configuration: In the post-request scripts of API A, add a variable extraction action to capture the required value from the response and store it in a variable.
  2. API B Configuration: Reference the extracted variable directly in API B's request parameters using the double curly brace syntax {{variableName}}.

API A Configuration

Open API A's test case and navigate to the Post-request Scripts section. Add an extraction action to capture the desired value from the response. For instance, to extract a token value from the response JSON and store it in a variable named petId:

API B Configuration

In API B's request parameters, directly reference the extracted variable using {{petId}}. When the request executes, Apifox automatically substitutes the placeholder with the stored value.

To verify correct variable reference, add a debug script in API B's pre-request section:

const storedId = pm.variables.get("petId");

console.log("Retrieved petId:", storedId);

This outputs the extracted value to the console, confirming successful variable population from API A's response.

JSONPath Introduction

JSONPath provides a declarative syntax for extracting specific values from JSON documents, analogous to how XPath operates on XML structures. Understanding JSONPath enables efficient navigation and extraction of nested data structures commonly encountered in API responses.

If you're unfamiliar with JSONPath syntax, various AI-powered tools can generate appropriate path expressions for your specific extraction needs.

Syntax Overview

The JSONPath language follows these fundamental rules:

  1. Root Reference: The $ symbol represents the root document, regardless of whether the root is an object or array.
  2. Node Navigation: Both dot notation and bracket notation are supported. For example, $.store.book[0].title and $['store']['book'][0]['title'] are equivalent.
  3. Expression Support: Parenthesized expressions like $.store.book[(@.length-1)].title enable dynamic indexing, such as accessing the last item in an array.
  4. Current Context: The @ symbol represents the current element within filter expressions.
  5. Filtering: Boolean expressions filter results based on conditions: $.store.book[?(@.price < 10)].title retrieves titles of books priced under 10.

Complete Syntax Reference

Core Concepts:

JSONPath and XPath Comparison:

Important Notes:

  • JSONPath array indices begin at 0, unlike XPath which starts at 1
  • String literals in JSONPath require single quotes: $.store.book[?(@.category=='reference')]

JSONPath Examples

Given the following JSON document:

{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            },
            {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            },
            {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
            }
        ],
        "bicycle": {
            "color": "red",
            "price": 19.95
        }
    }
}

Extraction Examples:

Script Usage

Script Engine Overview

Apifox incorporates a JavaScript-based script engine that enables dynamic behavior during API testing and collection execution. Scripts can modify requests before sending, validate responses after receipt, extract and manipulate data, and coordinate complex testing workflows.

Script Capabilities:

  • Response Validation: Use post-request scripts to assert that responses meet expected criteria
  • Dynamic Request Modification: Pre-request scripts can alter request parameters, add computed fields like signatures
  • Variable Management: Scripts can read, write, and transfer data between environment, global, and temporary variables
  • Hierarchical Configuration: Scripts can be defined at global, folder, and individual API levels
  • Execution Order: Global pre-request → Folder pre-request → API pre-request → Request → API post-request → Folder post-request → Global post-request
  • Console Debugging: Use console.log() statements in scripts; output appears in the console panel
  • External Program Support: Scripts can invoke programs written in Java, Python, PHP, Go, Ruby, Lua, and other languages

Apifox maintains full compatibility with Postman script syntax, enabling straightforward migration of existing Postman scripts.

Pre-request Scripts

Pre-request scripts execute before API requests are transmitted, enabling dynamic content generation for headers, URL parameters, and body content. These scripts use JavaScript and share syntax with post-request scripts, though they lack access to the pm.response object since responses haven't been received.

Example - Setting Environment Variables with Timestamps

When request parameters require timestamps:

  1. Create a script that generates the current timestamp
  2. Store the timestamp in an environment variable
  3. Reference the variable in request parameters using {{timestamp}}

Upon request execution, the pre-request script runs, setting the environment variable to the current timestamp value, which then replaces the variable reference.

Example - Obtaining and Setting Authentication Tokens

When requests require bearer tokens or API keys in headers:

// Retrieve authentication token from credential service
const authEndpoint = 'https://api.example.com/v1/authenticate?appKey=abc123&appSecret=secret456';

pm.sendRequest(authEndpoint, (err, response) => {
    if (err) {
        console.error('Authentication failed:', err);
        return;
    }

    const responseData = JSON.parse(response.text());
    const accessToken = responseData.accessToken;

    console.log('Obtained token:', accessToken);

    // Method 1: Store token in environment variable for reuse
    // pm.environment.set('authToken', accessToken);

    // Method 2: Directly add to request headers
    pm.request.headers.add({
        key: 'Authorization',
        value: `Bearer ${accessToken}`
    });
});

Post-request Scripts

Post-request scripts execute after receiving API responses, enabling assertion validation, response data extraction, and variable population for downstream requests.

Example - Response Assertion Tests

// Verify HTTP status code
pm.test('Expected status code 200', () => {
    pm.response.to.have.status(200);
});

// Environment verification
pm.test('Running against production environment', () => {
    pm.expect(pm.environment.get('deploymentEnv')).to.equal('production');
});

// Response body validation
pm.test('Response contains no errors', () => {
    pm.response.to.not.be.error;
    pm.response.to.have.jsonBody('');
    pm.response.to.not.have.jsonBody('error_code');
});

// Comprehensive response checks
pm.test('Response validation', () => {
    pm.response.to.be.ok;
    pm.response.to.have.body();
    pm.response.to.be.json;
});

Example - Storing Response Data in Variables

// Parse JSON response
const responsePayload = pm.response.json();

// Extract token and store for subsequent requests
pm.environment.set('sessionToken', responsePayload.access_token);

Shared Scripts

Shared scripts enable code reuse across multiple APIs, eliminating duplication of common functionality. Frequently used utility functions, authentication helpers, and data transformation methods can be defined once and referenced wherever needed.

Managing Shared Scripts: Access shared script management through Project Settings → Shared Scripts menu.

Referencing Shared Scripts: In any API's pre-request or post-request sections, reference shared scripts. Shared scripts execute before API-specific scripts, and their execution order matches their addition order.

Script Interaction Guidelines:

  • Scripts execute in isolated scopes to prevent variable conflicts
  • Local variables declared with var, let, const, or function are inaccessible to other scripts
  • To share variables or functions, declare them as globals (without keyword)

Variable Declaration Examples:

// Local variable (not accessible externally)
const privateValue = "internal_data";

// Convert to global for cross-script access
sharedValue = "accessible_data";

// Local function (not accessible externally)
function processData(input) {
    return input.toUpperCase();
}

// Global function (accessible to other scripts)
processData = (input) => {
    return input.toUpperCase();
};

pm Object API Reference

Global Objects

pm Object

The pm object provides access to runtime information, request/response data, and variable management capabilities.

  • pm.info: Runtime information object containing execution context
    • pm.info.eventName: Current script type ('prerequest' or 'test')
    • pm.info.iteration: Current iteration number (collection runs)
    • pm.info.iterationCount: Total iteration count
    • pm.info.requestName: Current test case name
    • pm.info.requestId: Unique identifier for current request

pm.sendRequest Function

Asynchronously sends HTTP/HTTPS requests from within scripts:

// Simple GET request
pm.sendRequest('https://httpbin.org/headers', (err, response) => {
    if (err) {
        console.error('Request failed:', err);
    } else {
        pm.environment.set('responseData', response.json());
    }
});

// Complete request configuration
const postRequest = {
    url: 'https://httpbin.org/post',
    method: 'POST',
    header: {
        'Content-Type': 'application/json',
        'X-Custom-Header': 'custom-value'
    },
    body: {
        mode: 'raw',
        raw: JSON.stringify({ username: 'testuser', active: true })
    }
};

pm.sendRequest(postRequest, (err, response) => {
    console.log(err ? err : response.json());
});

Variable Management

Temporary Variables (scoped to single request execution):

Variable Priority: Temporary variables override environment variables, which override global variables.

Environment Variables (scoped to environment):

Global Variables (scoped to project):

Request and Response Objects

pm.request Object

In pre-request scripts, represents the request about to be sent. In post-request scripts, represents the request that was sent.

pm.response Object (post-request only):

Testing and Assertion Methods

pm.test Function

// Synchronous assertion
pm.test('Status verification', () => {
    pm.response.to.have.status(200);
});

// Asynchronous assertion
pm.test('Async validation', (done) => {
    setTimeout(() => {
        pm.expect(pm.response.code).to.equal(200);
        done();
    }, 1000);
});

pm.expect Assertions

Use ChaiJS expect syntax for flexible assertions:

Response Assertions

Built-in JavaScript Libraries

Encoding and Cryptography Libraries

  • crypto-js (v3.1.9-1): Comprehensive cryptography library supporting AES, DES, HMAC, MD5, RIPEMD, SHA, and Base64 encoding/decoding
  • atob / btoa: Native Base64 encoding and decoding functions
  • jsrsasign (v10.3.0): RSA encryption and digital signatures
  • tv4 (v1.3.0): JSON Schema validation
  • xml2js (v0.4.19): XML to JSON conversion

Testing and Utilities

  • chai (v4.2.0): BDD/TDD assertion library supporting expect, should, and assert styles
  • postman-collection (v3.4.0): Postman collection SDK utilities
  • cheerio (v0.22.0): jQuery-like DOM manipulation for HTML parsing
  • lodash (v4.17.11): Utility functions for arrays, objects, strings
  • moment (v2.22.2): Date and time manipulation
  • uuid: Universal unique identifier generation
  • csv-parse (v1.2.4): CSV parsing and serialization
  • iconv-lite: Character encoding conversion supporting dozens of encodings
  • mockjs: Mock data generation and Ajax request interception

Validation Libraries

  • ajv (v6.6.2): High-performance JSON Schema validator

Node.js Built-in Modules

Apifox includes these Node.js modules: path, assert, buffer, util, url, punycode, querystring, string-decoder, stream, timers, events

Library Usage Examples

SHA256 Hashing:

// Import crypto-js library
const crypto = require('crypto-js');

// Message to hash
const input = 'Hello, World!';

// Generate SHA256 hash
const hash = crypto.SHA256(input);

// Convert to Base64
const base64Hash = crypto.enc.Base64.stringify(hash);

console.log('SHA256:', base64Hash);

HMAC-SHA256:

const crypto = require('crypto-js');

const message = 'Hello, World!';
const secretKey = 'supersecretkey';

const hmac = crypto.HMAC.SHA256(message, secretKey);
const base64Hmac = crypto.enc.Base64.stringify(hmac);

console.log('HMAC-SHA256:', base64Hmac);

Base64 Encoding/Decoding:

// Encoding
const crypto = require('crypto-js');
const originalText = 'Hello, Apifox!';

const encoded = crypto.enc.Base64.stringify(
    crypto.enc.Utf8.parse(originalText)
);
console.log('Encoded:', encoded);

// Decoding JSON response
const base64Response = pm.response.text();
const decoded = crypto.enc.Base64.parse(base64Response)
    .toString(crypto.enc.Utf8);

console.log('Decoded:', decoded);

AES Encryption:

const crypto = require('crypto-js');

// Retrieve secret from environment
const secretData = pm.environment.get('sensitiveData');

// Configure encryption parameters
const encryptionKey = crypto.enc.Utf8.parse('16-byte-secret-key!');
const initializationVector = crypto.enc.Utf8.parse('16-byte-iv-vector');

// Perform AES encryption
const encrypted = crypto.AES.encrypt(secretData, encryptionKey, {
    iv: initializationVector,
    mode: crypto.mode.CBC,
    padding: crypto.pad.Pkcs7
}).toString();

// Store encrypted value
pm.environment.set('encryptedData', encrypted);

AES Decryption:

const crypto = require('crypto-js');

// Encrypted data (typically from response)
const encryptedContent = 'gYQrJi5xPLkBrxmzcvqK6A==';

// Decryption key (16/24/32 bytes)
const key = crypto.enc.Utf8.parse('1234567890123456');

// Perform decryption (ECB mode example)
const decrypted = crypto.AES.decrypt(encryptedContent, key, {
    mode: crypto.mode.ECB,
    padding: crypto.pad.Pkcs7
}).toString(crypto.enc.Utf8);

console.log('Decrypted:', decrypted);

RSA Encryption:

const rsa = require('jsrsasign');

// Public key from environment or config
const publicKeyPEM = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
`;

// Encrypt message
const plainText = 'Hello, Apifox!';
const pubKey = rsa.KEYUTIL.getKey(publicKeyPEM);

const encryptedHex = rsa.KJUR.crypto.Cipher.encrypt(plainText, pubKey);
console.log('Encrypted:', encryptedHex);

RSA Decryption:

const rsa = require('jsrsasign');

// Private key from secure storage
const privateKeyPEM = `
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
-----END PRIVATE KEY-----
`;

// Ciphertext to decrypt
const ciphertext = 'a1b2c3d4...';

// Decrypt
const privKey = rsa.KEYUTIL.getKey(privateKeyPEM);
const decrypted = rsa.KJUR.crypto.Cipher.decrypt(ciphertext, privKey);

console.log('Decrypted:', decrypted);

External NPM Libraries

Use fox.liveRequire() to dynamicallly load NPM packages:

// Load single package
fox.liveRequire('md5', (md5) => {
    console.log('MD5 hash:', md5('message'));
});

// Load multiple packages
fox.liveRequire(['lodash', 'axios'], ([_, axios]) => {
    console.log('Lodash loaded');
});

Requirements:

  • Apifox version 1.4.5 or higher
  • Internet connection for library download
  • Desktop client required (not supported in web version)
  • Browser-compatible packages only (no native modules)

Script Examples and Patterns

Variable Operations

Environment Variables:

// Store value
pm.environment.set('apiKey', 'value123');

// Retrieve value
const storedKey = pm.environment.get('apiKey');

// Remove variable
pm.environment.unset('apiKey');

// Complex data storage
const dataArray = [1, 2, 3, 4];
pm.environment.set('arrayData', JSON.stringify(dataArray));

const dataObject = { user: 'admin', active: true };
pm.environment.set('objectData', JSON.stringify(dataObject));

// Retrieve and parse
try {
    const arrayData = JSON.parse(pm.environment.get('arrayData'));
    const objectData = JSON.parse(pm.environment.get('objectData'));
} catch (error) {
    console.error('Parse error:', error);
}

Global Variables:

pm.globals.set('globalToken', 'token-value');
const globalToken = pm.globals.get('globalToken');

Temporary Variables:

pm.variables.set('tempValue', 'temporary-data');
const tempValue = pm.variables.get('tempValue');

Request Inspection and Modification

URL Access:

const urlInfo = pm.request.url;
const fullUrl = urlInfo.toString();
const protocol = urlInfo.protocol;
const port = urlInfo.port;

Header Manipulation:

// Retrieve headers
const headers = pm.request.headers;
const contentType = headers.get('Content-Type');
const allHeaders = headers.toObject();

// Modify headers
headers.add({ key: 'X-Custom', value: 'custom-value' });
headers.upsert({ key: 'X-Request-ID', value: 'req-12345' });

Query Parameters:

const queryParams = pm.request.url.query;
const paramValue = queryParams.get('page');
const allParams = queryParams.toObject();

// Modify query
queryParams.add({ key: 'sort', value: 'desc' });
queryParams.upsert({ key: 'limit', value: '100' });

Request Body Access:

// Get current body as JSON
const bodyContent = pm.request.body.toJSON();
const bodyString = bodyContent.raw;

// Parse and modify
const parsedBody = JSON.parse(bodyString);
parsedBody.id = 999;
pm.request.body.update(JSON.stringify(parsedBody, null, 2));

// Using variable replacement for variable substitution
const processedBody = pm.variables.replaceIn(pm.request.body.raw);

Form Data Handling:

const formData = pm.request.body.formdata;
const fieldValue = formData.get('username');
const allFields = formData.toObject();

// Update form data
pm.request.body.update({
    mode: 'formdata',
    formdata: [
        { key: 'username', value: 'newuser' },
        { key: 'email', value: 'user@example.com' }
    ]
});

Assertion Patterns

Status Code Assertions:

pm.test('Status code validation', () => {
    pm.response.to.have.status(201);
    pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);
});

Response Body Assertions:

pm.test('Body content validation', () => {
    pm.response.to.have.body('expected string');
    pm.expect(pm.response.text()).to.include('search term');
});

JSON Data Assertions:

pm.test('JSON schema validation', () => {
    const data = pm.response.json();
    pm.expect(data.status).to.equal('success');
    pm.expect(data.items).to.have.lengthOf(5);
    pm.expect(data.user.id).to.be.a('number');
});

Header Assertions:

pm.test('Header validation', () => {
    pm.response.to.have.header('Content-Type');
    pm.expect(pm.response.headers.get('Content-Type'))
        .to.include('application/json');
});

Timing Assertions:

pm.test('Performance check', () => {
    pm.expect(pm.response.responseTime).to.be.below(500);
});

Post-request Assertions Configuration

Apifox provides a visual interface for configuring assertions in the Post-request Scripts section. Using JSONPath expressions, you can specify which response elements to validate.

For example, to verify a specific response field: $.data.status

The $ symbol represents the root object, and subsequent path segments navigate through the response structure.

After test execution, assertion results display in the test results panel, showing pass/fail status for each configured assertion along with detailed error messages for failures.

Tags: apifox api-testing pre-request-scripts post-request-scripts automation-testing

Posted on Sun, 19 Jul 2026 16:45:15 +0000 by phillfox