On this page
Docs / Scripting

Overview

RestForge includes a powerful JavaScript scripting engine that lets you automate workflows, test API responses, and manipulate request/response data dynamically. Scripts enable advanced use cases that go far beyond simple HTTP requests.

With scripting, you can:

RestForge supports two types of scripts that run at different stages of the request lifecycle:

Script Execution Order1. Pre-Request Script (runs BEFORE the HTTP request is sent) 2. HTTP Request (sent to server) 3. HTTP Response (received from server) 4. Post-Response Script (runs AFTER the HTTP response is received)

Scripts execute locally on your iPhone or iPad using a high-performance JavaScript engine. All pm.* APIs run in a secure sandbox with no access to device resources beyond the app's own data.

Postman Compatibility RestForge scripting is fully compatible with Postman's scripting syntax. You can copy/paste scripts between Postman and RestForge without modification in most cases. If you encounter compatibility issues, please report them via the Feedback tab.

Pre-Request Scripts

Pre-request scripts run immediately before the HTTP request is sent to the server. They're ideal for preparing dynamic data, setting authentication tokens, generating timestamps, or modifying request parameters based on runtime conditions.

Where to Write Pre-Request Scripts

Navigate to the Scripts tab in your request, then select the Pre-request sub-tab. The editor provides syntax highlighting, autocomplete for pm.* APIs, and 80+ built-in snippets.

When Pre-Request Scripts Run

Pre-request scripts execute in this order when you tap Send:

  1. Collection-level pre-request script (if request is in a collection)
  2. Folder-level pre-request script (if request is in a folder)
  3. Request-level pre-request script
  4. HTTP request is sent with modified data

Common Use Cases

Example: Generate Timestamp and Set Custom Header// Generate ISO 8601 timestamp const timestamp = new Date().toISOString(); // Set environment variable for reuse in other requests pm.environment.set('current_timestamp', timestamp); // Add custom header to this request pm.request.headers.add({ key: 'X-Request-Time', value: timestamp }); console.log('Request timestamp:', timestamp);
Example: Generate UUID for Request ID// Generate a random UUID v4 function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } const requestId = uuid(); pm.environment.set('request_id', requestId); pm.request.headers.add({key: 'X-Request-ID', value: requestId});

Post-Response Scripts

Post-response scripts run immediately after the HTTP response is received from the server. They're essential for extracting data from responses, writing automated tests, updating variables for chained requests, and validating API contracts.

Where to Write Post-Response Scripts

Navigate to the Scripts tab in your request, then select the Post-response sub-tab (also called "Tests" tab in the UI, since most post-response scripts are used for testing).

When Post-Response Scripts Run

Post-response scripts execute in this order after receiving the HTTP response:

  1. HTTP response is received and parsed
  2. Collection-level post-response script (if applicable)
  3. Folder-level post-response script (if applicable)
  4. Request-level post-response script
  5. Test results are displayed in the Tests tab with pass/fail indicators

Common Use Cases

Example: Extract Token from Login Response// Parse JSON response const response = pm.response.json(); // Extract access token from response if (response.access_token) { // Save to environment variable pm.environment.set('auth_token', response.access_token); // Also save refresh token if present if (response.refresh_token) { pm.environment.set('refresh_token', response.refresh_token); } console.log('Auth token saved to environment'); } else { console.error('No access_token found in response'); }
Example: Extract Pagination Cursor// Get response data const data = pm.response.json(); // Check if there's a next page cursor if (data.pagination && data.pagination.next_cursor) { pm.environment.set('next_cursor', data.pagination.next_cursor); console.log('Next cursor:', data.pagination.next_cursor); } else { pm.environment.unset('next_cursor'); console.log('No more pages'); }

pm.request API

The pm.request object provides access to the current HTTP request. You can read and modify the request's method, URL, headers, body, and authentication settings from your pre-request script.

Available Properties

Property Type Description
pm.request.method String HTTP method (GET, POST, PUT, PATCH, DELETE, etc.)
pm.request.url Object URL object with protocol, host, path, query, hash properties
pm.request.headers Object HeaderList with add(), remove(), upsert() methods
pm.request.body Object Request body with mode, raw, urlencoded, formdata properties
pm.request.auth Object Authentication configuration (type, credentials)
Example: Modify Request URL Dynamically// Get base URL from environment const baseUrl = pm.environment.get('api_base_url'); // Build dynamic path based on user ID const userId = pm.environment.get('user_id'); const newUrl = `${baseUrl}/users/${userId}/profile`; // Update request URL pm.request.url = newUrl; console.log('Request URL updated to:', newUrl);
Example: Add Authorization Header// Get token from environment const token = pm.environment.get('auth_token'); // Add Bearer token to request headers if (token) { pm.request.headers.add({ key: 'Authorization', value: `Bearer ${token}` }); }

pm.response API

The pm.response object provides access to the HTTP response received from the server. It's only available in post-response scripts and offers methods to parse JSON, read headers, check status codes, and measure response time.

Available Properties & Methods

Property/Method Type Description
pm.response.code Number HTTP status code (200, 404, 500, etc.)
pm.response.status String HTTP status message ("OK", "Not Found", etc.)
pm.response.headers Object Response headers as key-value pairs
pm.response.body String Raw response body as string
pm.response.responseTime Number Response time in milliseconds
pm.response.json() Function Parse response body as JSON object
pm.response.text() Function Get response body as text (same as .body)
Example: Check Response Status and Parse JSON// Check if response is successful if (pm.response.code === 200) { // Parse JSON response const data = pm.response.json(); // Extract specific fields const userId = data.id; const userName = data.name; // Save to environment for next request pm.environment.set('user_id', userId); pm.environment.set('user_name', userName); console.log(`User ${userName} (ID: ${userId}) loaded successfully`); } else { console.error('Request failed with status:', pm.response.status); }
Example: Read Response Headers// Get specific header const contentType = pm.response.headers.get('Content-Type'); const rateLimit = pm.response.headers.get('X-RateLimit-Remaining'); console.log('Content-Type:', contentType); console.log('Rate limit remaining:', rateLimit); // Check response time if (pm.response.responseTime > 1000) { console.warn('Slow response:', pm.response.responseTime, 'ms'); }

pm.environment API

The pm.environment object allows you to read, write, and delete environment variables from your scripts. Environment variables are scoped to the currently active environment and are perfect for configuration that changes between dev, staging, and production.

Available Methods

Example: Save Access Token to Environment// Parse login response const response = pm.response.json(); // Extract token and expiry const accessToken = response.access_token; const expiresIn = response.expires_in; // seconds until expiration // Calculate expiry timestamp const expiryTime = Date.now() + (expiresIn * 1000); // Save to environment pm.environment.set('access_token', accessToken); pm.environment.set('token_expiry', expiryTime); console.log('Token saved, expires at:', new Date(expiryTime).toISOString());
Example: Use Environment Variable in Request// Get API base URL from environment const baseUrl = pm.environment.get('api_base_url') || 'https://api.example.com'; // Get user ID from previous response const userId = pm.environment.get('current_user_id'); // Build request URL pm.request.url = `${baseUrl}/users/${userId}/orders`; console.log('Fetching orders for user:', userId);
See Also: Environments Guide For a complete guide on creating and managing environments, see the Environments documentation.

pm.globals API

The pm.globals object provides access to global variables that persist across all environments, collections, and requests. Globals are useful for truly universal values like API keys, user preferences, or feature flags.

Interface

The pm.globals API is identical to pm.environment:

Collection Variables

RestForge also supports collection-scoped variables via pm.collectionVariables.get(name). These are read-only in scripts (they can only be set via the Collection Settings UI).

Example: Global vs Environment vs Collection Variables// Global: available everywhere (e.g., user preference) const theme = pm.globals.get('ui_theme') || 'light'; // Environment: changes per environment (e.g., dev vs prod API) const apiUrl = pm.environment.get('api_base_url'); // Collection: scoped to this collection only (read-only) const collectionVersion = pm.collectionVariables.get('version'); console.log('Theme:', theme); console.log('API URL:', apiUrl); console.log('Collection version:', collectionVersion);

Variable Precedence

When multiple variable scopes define the same variable name, RestForge resolves them in this order (highest to lowest priority):

  1. Environment variables
  2. Collection variables
  3. Global variables

pm.test & pm.expect

RestForge includes a full-featured testing framework based on Chai assertions. You can write test cases that validate response status codes, headers, JSON structure, response times, and complex business logic. Test results appear in the Tests tab with green checkmarks for passes and red X marks for failures.

Writing Tests with pm.test()

The pm.test(name, function) method defines a named test case. Inside the test function, use pm.expect() to make assertions.

Basic Test Structurepm.test("Test name", function() { pm.expect(actualValue).to.equal(expectedValue); });

Common Assertions

Assertion Description
.to.equal(value) Strict equality (===)
.to.eql(value) Deep equality (for objects and arrays)
.to.be.a(type) Type check ('string', 'number', 'object', 'array')
.to.include(value) Array/string contains value
.to.have.property(key) Object has property
.to.be.above(number) Greater than (>)
.to.be.below(number) Less than (<)
.to.be.true / .to.be.false Boolean checks
.to.have.lengthOf(n) Array/string length equals n
.to.match(regex) String matches regular expression
Example: Comprehensive Test Suite for User API// Test 1: Status code is 200 pm.test("Status code is 200", function() { pm.expect(pm.response.code).to.equal(200); }); // Test 2: Response time is acceptable pm.test("Response time is below 500ms", function() { pm.expect(pm.response.responseTime).to.be.below(500); }); // Test 3: Content-Type is JSON pm.test("Content-Type is application/json", function() { pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json'); }); // Test 4: Response has required fields pm.test("Response has user data", function() { const data = pm.response.json(); pm.expect(data).to.have.property('id'); pm.expect(data).to.have.property('name'); pm.expect(data).to.have.property('email'); }); // Test 5: Field types are correct pm.test("Field types are valid", function() { const data = pm.response.json(); pm.expect(data.id).to.be.a('number'); pm.expect(data.name).to.be.a('string'); pm.expect(data.email).to.be.a('string'); }); // Test 6: Email format is valid pm.test("Email format is valid", function() { const data = pm.response.json(); pm.expect(data.email).to.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); }); // Test 7: User is active pm.test("User account is active", function() { const data = pm.response.json(); pm.expect(data.status).to.equal('active'); });

Test Results Display

After running your request, switch to the Tests tab to see results. Passing tests show a green checkmark, failing tests show a red X with the assertion error message. You'll also see the total pass/fail count and execution time.

pm.sendRequest

The pm.sendRequest() API allows you to make additional HTTP requests from within your scripts. This is powerful for implementing complex workflows like token refresh, dependency fetching, webhooks, or multi-step authentication flows.

Basic Usage: Simple GET Request

Simple URL String + Callbackpm.sendRequest('https://api.example.com/status', function(err, response) { if (err) { console.error('Request failed:', err); return; } console.log('Status:', response.code); console.log('Body:', response.json()); });

Advanced Usage: Full Request Specification

For POST, PUT, PATCH, DELETE requests or when you need to set headers and body, pass a request specification object:

Request Spec Objectconst requestSpec = { url: 'https://api.example.com/data', method: 'POST', header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + pm.environment.get('token') }, body: { mode: 'raw', raw: JSON.stringify({ key: 'value', timestamp: Date.now() }) } }; pm.sendRequest(requestSpec, function(err, response) { if (err) { console.error(err); return; } const data = response.json(); console.log('Response:', data); });

Response Object Properties

Property Type Description
response.code Number HTTP status code
response.status String HTTP status message
response.headers Object Response headers (use .get() method)
response.json() Function Parse response as JSON
response.text() Function Get response as text
response.responseTime Number Response time in milliseconds
response.responseSize Number Response size in bytes

Real-World Example: Token Refresh Pattern

Automatic Token Refresh in Pre-Request Script// Check if token is expired const tokenExpiry = pm.environment.get('token_expiry'); const now = Date.now(); if (!tokenExpiry || now >= tokenExpiry) { console.log('Token expired or missing, refreshing...'); // Refresh token request const refreshToken = pm.environment.get('refresh_token'); pm.sendRequest({ url: pm.environment.get('auth_url') + '/refresh', method: 'POST', header: { 'Content-Type': 'application/json' }, body: { mode: 'raw', raw: JSON.stringify({ refresh_token: refreshToken }) } }, function(err, response) { if (err || response.code !== 200) { console.error('Token refresh failed'); return; } const data = response.json(); // Save new token pm.environment.set('access_token', data.access_token); pm.environment.set('token_expiry', Date.now() + (data.expires_in * 1000)); console.log('Token refreshed successfully'); }); } else { console.log('Token still valid'); }

Safety Limits

To prevent infinite loops and resource exhaustion, pm.sendRequest() has these safety limits:

Postman Compatibility RestForge's pm.sendRequest() API is fully compatible with Postman's implementation. Scripts using this API can be copied between Postman and RestForge without modification.

pm.execution

The pm.execution object provides control over script execution flow. Currently, it supports skipping the HTTP request conditionally via pm.execution.skipRequest().

pm.execution.skipRequest()

Call this method from a pre-request script to prevent the HTTP request from being sent. This is useful for:

Example: Skip Request Based on Feature Flag// Check if feature is enabled const featureEnabled = pm.environment.get('feature_xyz_enabled'); if (featureEnabled !== 'true') { console.log('Feature XYZ is disabled, skipping request'); pm.execution.skipRequest(); }
Example: Skip Request if Cache is Valid// Check cache expiry const cacheExpiry = pm.globals.get('user_data_cache_expiry'); const now = Date.now(); if (cacheExpiry && now < cacheExpiry) { console.log('Cache is still valid, skipping API request'); pm.execution.skipRequest(); // Use cached data instead const cachedData = JSON.parse(pm.globals.get('user_data_cache')); console.log('Using cached data:', cachedData); } else { console.log('Cache expired, fetching fresh data'); }

Console & Logging

RestForge supports standard JavaScript console methods for debugging and logging. All console output appears in the Console tab at the bottom of the request screen.

Available Methods

Example: Debug Logging// Log variable values const userId = pm.environment.get('user_id'); console.log('Processing user ID:', userId); // Log object inspection const response = pm.response.json(); console.log('Full response:', response); // Warning for slow responses if (pm.response.responseTime > 1000) { console.warn('Slow response detected:', pm.response.responseTime, 'ms'); } // Error logging if (pm.response.code >= 400) { console.error('Request failed with status:', pm.response.code, pm.response.status); }

Viewing Console Output

After running your request, tap the Console tab at the bottom of the screen. You'll see timestamped log entries with color-coded severity levels. The console automatically clears when you run a new request.

Built-in Snippets

RestForge includes 80+ pre-written code snippets that you can insert into your scripts with a single tap. Snippets are organized into categories and cover the most common scripting patterns.

Snippet Categories

Category Example Snippets
Variables Set environment variable, Get environment variable, Clear variable, Set global variable
Assertions Status code is 200, Response time < 200ms, Body contains string, JSON value check, Header exists
Data Extraction Extract JSON field, Get response header, Parse cookies, Extract array item, Get nested property
Generation Generate UUID, Random integer, Random string, Current timestamp, ISO 8601 date
Encoding Base64 encode/decode, URL encode/decode, MD5 hash, SHA256 hash, HMAC signature

How to Insert Snippets

  1. In the Scripts tab, tap the Snippets button in the toolbar
  2. Browse or search for the snippet you need
  3. Tap the snippet to insert it at your cursor position
  4. Customize the inserted code with your variable names and values
Pro Tip: Learn by Example Snippets are an excellent way to learn the scripting API. Insert a snippet, read the code, and modify it to fit your use case. Most snippets include helpful comments explaining what each line does.

Examples & Recipes

Here are complete, real-world examples demonstrating common scripting patterns. You can copy these recipes and adapt them to your API workflows.

Recipe 1: OAuth Token Chain

Automatically fetch an OAuth token before every authenticated request.

Collection-Level Pre-Request Script// Check if we have a valid token const token = pm.environment.get('oauth_token'); const tokenExpiry = pm.environment.get('oauth_token_expiry'); const now = Date.now(); // If no token or token expired, fetch new one if (!token || !tokenExpiry || now >= tokenExpiry) { console.log('Fetching new OAuth token...'); const clientId = pm.environment.get('oauth_client_id'); const clientSecret = pm.environment.get('oauth_client_secret'); const tokenUrl = pm.environment.get('oauth_token_url'); pm.sendRequest({ url: tokenUrl, method: 'POST', header: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: { mode: 'urlencoded', urlencoded: [ {key: 'grant_type', value: 'client_credentials'}, {key: 'client_id', value: clientId}, {key: 'client_secret', value: clientSecret} ] } }, function(err, response) { if (err || response.code !== 200) { console.error('Token fetch failed:', err || response.code); return; } const data = response.json(); const expiresIn = data.expires_in || 3600; // Default 1 hour pm.environment.set('oauth_token', data.access_token); pm.environment.set('oauth_token_expiry', now + (expiresIn * 1000)); console.log('OAuth token refreshed, expires in', expiresIn, 'seconds'); }); }
Request-Level Pre-Request Script// Add token to Authorization header const token = pm.environment.get('oauth_token'); if (token) { pm.request.headers.add({ key: 'Authorization', value: `Bearer ${token}` }); }

Recipe 2: Dynamic Request Body with Timestamp

Generate request bodies with timestamps, signatures, or other dynamic fields.

Pre-Request Script for Signed API Request// Generate timestamp const timestamp = Date.now(); // Get API secret from environment const apiSecret = pm.environment.get('api_secret'); const apiKey = pm.environment.get('api_key'); // Build payload const payload = { api_key: apiKey, timestamp: timestamp, data: { userId: pm.environment.get('user_id'), action: 'update_profile' } }; // Generate signature (simple example, use HMAC in production) const signatureString = JSON.stringify(payload) + apiSecret; const signature = require('crypto-js').SHA256(signatureString).toString(); payload.signature = signature; // Set request body pm.request.body = { mode: 'raw', raw: JSON.stringify(payload) }; console.log('Request signed with timestamp:', timestamp);

Recipe 3: Complete Response Validation Suite

Validate response structure, data types, business logic, and performance in one script.

Post-Response Script for E-Commerce Order API// Test 1: Response is successful pm.test("Order created successfully", function() { pm.expect(pm.response.code).to.equal(201); }); // Test 2: Response time is acceptable pm.test("Response time is below 1 second", function() { pm.expect(pm.response.responseTime).to.be.below(1000); }); // Parse response const order = pm.response.json(); // Test 3: Response structure pm.test("Response has required fields", function() { pm.expect(order).to.have.property('orderId'); pm.expect(order).to.have.property('items'); pm.expect(order).to.have.property('total'); pm.expect(order).to.have.property('status'); }); // Test 4: Data types pm.test("Field types are correct", function() { pm.expect(order.orderId).to.be.a('string'); pm.expect(order.items).to.be.an('array'); pm.expect(order.total).to.be.a('number'); pm.expect(order.status).to.be.a('string'); }); // Test 5: Business logic - total matches sum of items pm.test("Order total matches sum of line items", function() { const calculatedTotal = order.items.reduce((sum, item) => { return sum + (item.price * item.quantity); }, 0); pm.expect(order.total).to.equal(calculatedTotal); }); // Test 6: Order has at least one item pm.test("Order contains items", function() { pm.expect(order.items.length).to.be.above(0); }); // Test 7: Status is valid pm.test("Order status is valid", function() { const validStatuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered']; pm.expect(validStatuses).to.include(order.status); }); // Save order ID for subsequent requests pm.environment.set('last_order_id', order.orderId); console.log('Order created:', order.orderId);

Recipe 4: Pagination Cursor Pattern

Automatically extract pagination cursors and prepare for the next page request.

Post-Response Script for Paginated API// Parse paginated response const response = pm.response.json(); // Validate response pm.test("Status code is 200", function() { pm.expect(pm.response.code).to.equal(200); }); pm.test("Response has data array", function() { pm.expect(response.data).to.be.an('array'); }); // Check pagination info if (response.pagination) { const pagination = response.pagination; // Log current page info console.log('Page size:', pagination.page_size); console.log('Total items:', pagination.total); console.log('Items in this page:', response.data.length); // Save next cursor if available if (pagination.next_cursor) { pm.environment.set('next_cursor', pagination.next_cursor); console.log('Next cursor saved:', pagination.next_cursor); console.log('To fetch next page, use cursor:', pagination.next_cursor); } else { pm.environment.unset('next_cursor'); console.log('No more pages available'); } // Save previous cursor for backward navigation if (pagination.previous_cursor) { pm.environment.set('previous_cursor', pagination.previous_cursor); } // Test: Pagination metadata is valid pm.test("Pagination metadata is valid", function() { pm.expect(pagination.page_size).to.be.a('number'); pm.expect(pagination.page_size).to.be.above(0); pm.expect(pagination.total).to.be.a('number'); }); // Test: Page size matches actual data length (unless last page) if (pagination.next_cursor) { pm.test("Page is full", function() { pm.expect(response.data.length).to.equal(pagination.page_size); }); } } else { console.log('No pagination info in response'); }
Pre-Request Script for Next Page (set query param)// Get next cursor from environment const nextCursor = pm.environment.get('next_cursor'); if (nextCursor) { // Add cursor to query params const url = pm.request.url; url.query.add({key: 'cursor', value: nextCursor}); console.log('Using cursor for next page:', nextCursor); } else { console.log('No cursor set, fetching first page'); }
Need More Examples? Check out the Collections guide for examples of organizing scripts across folders, and the Environments guide for advanced variable management patterns.