2
Scripts
Pavel Baksy edited this page 2026-01-13 16:59:00 +01:00

Scripts

Roster supports JavaScript preprocessing and postprocessing scripts to automate request modifications and response data extraction.

Overview

Scripts allow you to:

  • Modify requests before they're sent (preprocessing)
  • Extract data from responses after they're received (postprocessing)
  • Chain requests together by passing data between them
  • Automate workflows like authentication flows

Scripts are executed using GJS (GNOME JavaScript), the same JavaScript runtime used throughout GNOME.

Script Types

Preprocessing Scripts

Run BEFORE the HTTP request is sent.

Use cases:

  • Modify request headers, URL, body, or method
  • Add dynamic values (timestamps, request IDs, signatures)
  • Read environment variables
  • Set/update environment variables
  • Add authentication headers

Postprocessing Scripts

Run AFTER receiving the HTTP response.

Use cases:

  • Extract data from response body
  • Parse JSON/XML responses
  • Store values in environment variables for use in subsequent requests
  • Validate response data
  • Chain requests together

Adding Scripts to Requests

Step 1: Open Script Editor

Use the Scripts tab in the request editor

The script editor tab contains two panels:

  • Preprocessing panel
  • Postprocessing panel

Step 2: Write Your Script

  1. Select the appropriate panel
  2. Write JavaScript code
  3. Click "Save" or Ctrl+S

Step 3: Run Request with Scripts

  1. Open the request
  2. Click "Send"
  3. Preprocessing script runs first (if present)
  4. HTTP request sent
  5. Postprocessing script runs after response received (if present)

Preprocessing API

Available Objects

Request Object (Modifiable)

request.method    // String: "GET", "POST", "PUT", "DELETE"
request.url       // String: Full URL
request.headers   // Object: Header key-value pairs
request.body      // String: Request body

All properties can be modified.

Roster API

// Variables
roster.getVariable(name)           // Get variable from selected environment
roster.setVariable(name, value)    // Set/update variable
roster.setVariables({key: value})  // Batch set variables

// Project Information
roster.project.name                // Current project name
roster.project.environments        // Array of environment names

Console Output

console.log(message)    // Output shown in preprocessing results tab
console.error(message)  // Error output

Examples

Example 1: Add Dynamic Authentication Header

const token = roster.getVariable('auth_token');
request.headers['Authorization'] = 'Bearer ' + token;
request.headers['X-Request-Time'] = new Date().toISOString();
console.log('Added auth header');

Example 2: Modify Request Based on Environment

const env = roster.getVariable('environment_name');
if (env === 'production') {
    request.url = request.url.replace('localhost', 'api.example.com');
    console.log('Switched to production URL');
} else {
    console.log('Using development URL');
}

Example 3: Generate Request Signature

const apiKey = roster.getVariable('api_key');
const timestamp = Date.now().toString();
const requestId = Math.random().toString(36).substring(7);

request.headers['X-API-Key'] = apiKey;
request.headers['X-Timestamp'] = timestamp;
request.headers['X-Request-ID'] = requestId;

// Save for later reference
roster.setVariable('last_request_id', requestId);
console.log('Request ID:', requestId);

Example 4: Add HMAC Signature

// Note: GJS doesn't have crypto module, this is pseudocode
const apiKey = roster.getVariable('api_key');
const secretKey = roster.getVariable('secret_key');
const timestamp = Date.now().toString();

// You would use a crypto library here
const signature = generateHMAC(request.body + timestamp, secretKey);

request.headers['X-API-Key'] = apiKey;
request.headers['X-Timestamp'] = timestamp;
request.headers['X-Signature'] = signature;

Example 5: Modify Request Body

// Parse existing body
const body = JSON.parse(request.body);

// Add dynamic fields
body.timestamp = new Date().toISOString();
body.requestId = Math.random().toString(36).substring(7);
body.version = '2.0';

// Update request body
request.body = JSON.stringify(body, null, 2);
console.log('Modified request body');

Postprocessing API

Available Objects

Response Object (Read-Only)

response.body         // String: Response body
response.headers      // Object: Header key-value pairs
response.statusCode   // Number: HTTP status code (200, 404, etc.)
response.statusText   // String: Status text ("OK", "Not Found", etc.)
response.responseTime // Number: Response time in milliseconds

All properties are read-only.

Roster API

// Variables
roster.setVariable(name, value)    // Set/update variable
roster.setVariables({key: value})  // Batch set variables

Note: roster.getVariable() is NOT available in postprocessing.

Console Output

console.log(message)    // Output shown in postprocessing results tab
console.error(message)  // Error output

Examples

Example 1: Extract Authentication Token

const data = JSON.parse(response.body);
if (data.access_token) {
    roster.setVariable('auth_token', data.access_token);
    console.log('Saved auth token');
} else {
    console.error('No access token in response');
}

Example 2: Extract Multiple Values

const data = JSON.parse(response.body);
roster.setVariables({
    user_id: data.user.id,
    user_name: data.user.name,
    user_email: data.user.email,
    session_id: data.session.id
});
console.log('Extracted user:', data.user.name);

Example 3: Validate and Store Response

const data = JSON.parse(response.body);

if (response.statusCode === 200 && data.items) {
    roster.setVariable('item_count', data.items.length.toString());

    if (data.items.length > 0) {
        roster.setVariable('first_item_id', data.items[0].id);
        roster.setVariable('first_item_name', data.items[0].name);
    }

    console.log('Found', data.items.length, 'items');
} else {
    console.error('Error: Invalid response or no items');
}

Example 4: Extract Pagination Token

const data = JSON.parse(response.body);

if (data.next_page_token) {
    roster.setVariable('next_page', data.next_page_token);
    console.log('Next page token saved');
} else {
    roster.setVariable('next_page', '');
    console.log('No more pages');
}

Example 5: Parse Response Headers

// Extract rate limit information from headers
const rateLimit = response.headers['X-RateLimit-Limit'];
const rateRemaining = response.headers['X-RateLimit-Remaining'];
const rateReset = response.headers['X-RateLimit-Reset'];

if (rateLimit && rateRemaining && rateReset) {
    roster.setVariables({
        rate_limit: rateLimit,
        rate_remaining: rateRemaining,
        rate_reset: rateReset
    });
    console.log('Rate limit:', rateRemaining, '/', rateLimit);
} else {
    console.log('No rate limit headers');
}

Complete Workflows

Workflow 1: OAuth Token Flow

Request 1: Login (POST /auth/login)

Postprocessing:

// Extract and store tokens from login response
const data = JSON.parse(response.body);

if (response.statusCode === 200) {
    roster.setVariables({
        access_token: data.access_token,
        refresh_token: data.refresh_token,
        user_id: data.user_id,
        expires_at: data.expires_at
    });
    console.log('Logged in as user:', data.user_id);
} else {
    console.error('Login failed:', response.statusText);
}

Request 2: Get User Profile (GET /users/{userId})

Preprocessing:

// Use stored token and user ID in request
const token = roster.getVariable('access_token');
const userId = roster.getVariable('user_id');

// Add authentication
request.headers['Authorization'] = 'Bearer ' + token;

// Substitute user ID in URL
request.url = request.url.replace('{userId}', userId);

console.log('Making authenticated request for user:', userId);

Workflow 2: Paginated API Requests

Request: Get Items with Pagination

Preprocessing:

const nextPage = roster.getVariable('next_page');

if (nextPage) {
    request.url = request.url + '?page_token=' + nextPage;
    console.log('Fetching next page');
} else {
    console.log('Fetching first page');
}

Postprocessing:

const data = JSON.parse(response.body);

// Store items count
roster.setVariable('items_count', data.items.length.toString());

// Store next page token for subsequent request
if (data.next_page_token) {
    roster.setVariable('next_page', data.next_page_token);
    console.log('Page loaded. More pages available.');
} else {
    roster.setVariable('next_page', '');
    console.log('Page loaded. No more pages.');
}

Workflow 3: Dynamic API Versioning

Preprocessing:

const apiVersion = roster.getVariable('api_version') || 'v1';
request.url = request.url.replace('/api/', '/api/' + apiVersion + '/');
request.headers['X-API-Version'] = apiVersion;
console.log('Using API version:', apiVersion);

Postprocessing:

// Check if server suggests upgrading API version
const suggestedVersion = response.headers['X-Suggested-API-Version'];

if (suggestedVersion) {
    console.log('Server suggests API version:', suggestedVersion);
    roster.setVariable('suggested_api_version', suggestedVersion);
}

Script Execution Flow

When sending a request with scripts:

  1. Execute preprocessing script (if present) - can modify request
  2. Apply variable substitution ({{variable_name}})
  3. Send HTTP request
  4. Execute postprocessing script (if present) - can read response, set variables
  5. Display response and save to history

Error Handling

If a script throws an error, the error is shown in the script output panel. The request still executes (preprocessing) or response still displays (postprocessing). Variable changes before the error are preserved.

Always use try-catch for JSON parsing:

try {
    const data = JSON.parse(response.body);
    roster.setVariable('user_id', data.user.id);
} catch (e) {
    console.error('Parse error:', e.message);
}

Best Practices

  • Keep scripts simple - One clear purpose per script
  • Handle errors - Use try-catch for JSON parsing and check status codes
  • Use logging - Track execution with console.log for debugging
  • Never log secrets - Log confirmations, not actual token/key values

Limitations

No External Libraries

GJS environment is sandboxed:

  • Cannot import npm packages
  • Cannot require() external modules
  • Standard JavaScript built-ins available

No Asynchronous Operations

Scripts execute synchronously:

  • No setTimeout/setInterval
  • No async/await
  • No fetch() or XMLHttpRequest
  • Use Roster's request system instead

Security Restrictions

Scripts cannot:

  • Access file system directly
  • Make network requests (other than the main request)
  • Execute shell commands
  • Access system resources

Debugging Scripts

  • Use console.log liberally to track script execution
  • Check Preprocessing/Postprocessing panels for output and errors
  • Start with simple test scripts and build up complexity

Next Steps