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
- Select the appropriate panel
- Write JavaScript code
- Click "Save" or Ctrl+S
Step 3: Run Request with Scripts
- Open the request
- Click "Send"
- Preprocessing script runs first (if present)
- HTTP request sent
- 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:
- Execute preprocessing script (if present) - can modify request
- Apply variable substitution (
{{variable_name}}) - Send HTTP request
- Execute postprocessing script (if present) - can read response, set variables
- 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
- API-Reference - Complete API documentation
- Variables - Learn about environment variables
- Sensitive-Variables - Secure storage for tokens and keys