# Roster A modern HTTP client for GNOME, built with GTK 4 and libadwaita. ## Features - Send HTTP requests (GET, POST, PUT, DELETE) - Configure custom headers and request bodies - View response headers and bodies - Track request history with persistence - **JavaScript preprocessing and postprocessing scripts** - **Project environments with variables** - Beautiful GNOME-native UI ## Dependencies - GTK 4 - libadwaita 1 - Python 3 - libsoup3 (provided by GNOME Platform) - gjs (GNOME JavaScript) - for script execution ## Building ```bash meson setup builddir meson compile -C builddir sudo meson install -C builddir ``` ## Usage Roster uses libsoup3 (from GNOME Platform) for making HTTP requests - no external dependencies required. Run Roster from your application menu or with the `roster` command. ## Scripts Roster supports JavaScript preprocessing and postprocessing scripts to automate request modifications and response data extraction. ### Preprocessing Scripts **Run BEFORE the HTTP request is sent.** Use preprocessing to: - Modify request headers, URL, body, or method - Add dynamic values (timestamps, request IDs, signatures) - Read environment variables - Set/update environment variables **Available API:** ```javascript // Request object (modifiable) request.method // "GET", "POST", "PUT", "DELETE" request.url // Full URL string request.headers // Object with header key-value pairs request.body // Request body string // Roster API roster.getVariable(name) // Get variable from selected environment roster.setVariable(name, value) // Set/update variable roster.setVariables({key: value}) // Batch set variables roster.project.name // Current project name roster.project.environments // Array of environment names // Console output console.log(message) // Output shown in preprocessing results ``` **Example 1: Add Dynamic Authentication Header** ```javascript const token = roster.getVariable('auth_token'); request.headers['Authorization'] = 'Bearer ' + token; request.headers['X-Request-Time'] = new Date().toISOString(); console.log('Added auth header for token:', token); ``` **Example 2: Modify Request Based on Environment** ```javascript const env = roster.getVariable('environment_name'); if (env === 'production') { request.url = request.url.replace('localhost', 'api.example.com'); console.log('Switched to production URL'); } ``` **Example 3: Generate Request Signature** ```javascript 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); ``` ### Postprocessing Scripts **Run AFTER receiving the HTTP response.** Use postprocessing to: - Extract data from response body - Parse JSON/XML responses - Store values in environment variables for use in subsequent requests - Validate response data **Available API:** ```javascript // Response object (read-only) response.body // Response body as string response.headers // Object with header key-value pairs response.statusCode // HTTP status code (e.g., 200, 404) response.statusText // Status text (e.g., "OK", "Not Found") response.responseTime // Response time in milliseconds // Roster API roster.setVariable(name, value) // Set/update variable roster.setVariables({key: value}) // Batch set variables // Console output console.log(message) // Output shown in script results ``` **Example 1: Extract Authentication Token** ```javascript const data = JSON.parse(response.body); if (data.access_token) { roster.setVariable('auth_token', data.access_token); console.log('Saved auth token'); } ``` **Example 2: Extract Multiple Values** ```javascript const data = JSON.parse(response.body); roster.setVariables({ user_id: data.user.id, user_name: data.user.name, session_id: data.session.id }); console.log('Extracted user:', data.user.name); ``` **Example 3: Validate and Store Response** ```javascript 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); } console.log('Found', data.items.length, 'items'); } else { console.log('Error: Invalid response'); } ``` ### Workflow Example: OAuth Token Flow **Request 1 (Login) - Postprocessing:** ```javascript // Extract and store tokens from login response const data = JSON.parse(response.body); roster.setVariables({ access_token: data.access_token, refresh_token: data.refresh_token, user_id: data.user_id }); console.log('Logged in as user:', data.user_id); ``` **Request 2 (API Call) - Preprocessing:** ```javascript // Use stored token in subsequent request const token = roster.getVariable('access_token'); const userId = roster.getVariable('user_id'); request.headers['Authorization'] = 'Bearer ' + token; request.url = request.url.replace('{userId}', userId); console.log('Making authenticated request for user:', userId); ``` ### Environment Variables Variables can be: - Manually defined in "Manage Environments" - Automatically created by scripts using `roster.setVariable()` - Used in requests with `{{variable_name}}` syntax - Read in preprocessing with `roster.getVariable()` Variables are scoped to environments within projects, allowing different values for development, staging, and production.