Add comprehensive wiki documentation
parent
3da66bb11f
commit
72a00e5cd6
622
API-Reference.md
Normal file
622
API-Reference.md
Normal file
@ -0,0 +1,622 @@
|
|||||||
|
# API Reference
|
||||||
|
|
||||||
|
Complete JavaScript API reference for Roster preprocessing and postprocessing scripts.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Roster provides a JavaScript API accessible from [[Scripts]] for automating request modifications and response processing.
|
||||||
|
|
||||||
|
**Language:** JavaScript (ES5+)
|
||||||
|
**Runtime:** GJS (GNOME JavaScript)
|
||||||
|
**Context:** Sandboxed, synchronous execution
|
||||||
|
|
||||||
|
## Global Objects
|
||||||
|
|
||||||
|
### Preprocessing Script Context
|
||||||
|
|
||||||
|
Available in preprocessing scripts only:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
request // Modifiable request object
|
||||||
|
roster // Roster API (with getVariable)
|
||||||
|
console // Console output
|
||||||
|
```
|
||||||
|
|
||||||
|
### Postprocessing Script Context
|
||||||
|
|
||||||
|
Available in postprocessing scripts only:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
response // Read-only response object
|
||||||
|
roster // Roster API (without getVariable)
|
||||||
|
console // Console output
|
||||||
|
```
|
||||||
|
|
||||||
|
## Request Object
|
||||||
|
|
||||||
|
**Available in:** Preprocessing scripts only
|
||||||
|
**Type:** Mutable
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
#### `request.method`
|
||||||
|
|
||||||
|
**Type:** `string`
|
||||||
|
**Values:** `"GET"`, `"POST"`, `"PUT"`, `"DELETE"`
|
||||||
|
**Description:** HTTP method for the request
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Change method from GET to POST
|
||||||
|
request.method = "POST";
|
||||||
|
console.log('Method changed to:', request.method);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `request.url`
|
||||||
|
|
||||||
|
**Type:** `string`
|
||||||
|
**Description:** Complete URL for the request
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Add query parameter
|
||||||
|
request.url = request.url + '?timestamp=' + Date.now();
|
||||||
|
|
||||||
|
// Replace placeholder
|
||||||
|
const userId = roster.getVariable('user_id');
|
||||||
|
request.url = request.url.replace('{userId}', userId);
|
||||||
|
|
||||||
|
// Change domain
|
||||||
|
request.url = request.url.replace('localhost', 'api.example.com');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `request.headers`
|
||||||
|
|
||||||
|
**Type:** `object`
|
||||||
|
**Description:** HTTP headers as key-value pairs
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Add header
|
||||||
|
request.headers['Authorization'] = 'Bearer ' + token;
|
||||||
|
|
||||||
|
// Modify existing header
|
||||||
|
request.headers['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
// Delete header
|
||||||
|
delete request.headers['X-Old-Header'];
|
||||||
|
|
||||||
|
// Read header
|
||||||
|
const contentType = request.headers['Content-Type'];
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `request.body`
|
||||||
|
|
||||||
|
**Type:** `string`
|
||||||
|
**Description:** Request body content
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Set body
|
||||||
|
request.body = JSON.stringify({ name: "John", age: 30 });
|
||||||
|
|
||||||
|
// Modify existing body
|
||||||
|
const data = JSON.parse(request.body);
|
||||||
|
data.timestamp = new Date().toISOString();
|
||||||
|
request.body = JSON.stringify(data);
|
||||||
|
|
||||||
|
// Clear body
|
||||||
|
request.body = "";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Object
|
||||||
|
|
||||||
|
**Available in:** Postprocessing scripts only
|
||||||
|
**Type:** Immutable (read-only)
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
#### `response.body`
|
||||||
|
|
||||||
|
**Type:** `string`
|
||||||
|
**Description:** Response body content
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Parse JSON response
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
console.log('User name:', data.name);
|
||||||
|
|
||||||
|
// Check if response contains text
|
||||||
|
if (response.body.includes('error')) {
|
||||||
|
console.error('Response contains error');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get response length
|
||||||
|
console.log('Response size:', response.body.length, 'bytes');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `response.headers`
|
||||||
|
|
||||||
|
**Type:** `object`
|
||||||
|
**Description:** Response headers as key-value pairs (read-only)
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Read header
|
||||||
|
const contentType = response.headers['Content-Type'];
|
||||||
|
console.log('Content type:', contentType);
|
||||||
|
|
||||||
|
// Check if header exists
|
||||||
|
if (response.headers['X-Rate-Limit-Remaining']) {
|
||||||
|
const remaining = response.headers['X-Rate-Limit-Remaining'];
|
||||||
|
console.log('Rate limit remaining:', remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all headers
|
||||||
|
for (const key in response.headers) {
|
||||||
|
console.log(key + ':', response.headers[key]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `response.statusCode`
|
||||||
|
|
||||||
|
**Type:** `number`
|
||||||
|
**Description:** HTTP status code (200, 404, 500, etc.)
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Check if successful
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
console.log('Success!');
|
||||||
|
} else if (response.statusCode >= 400 && response.statusCode < 500) {
|
||||||
|
console.error('Client error:', response.statusCode);
|
||||||
|
} else if (response.statusCode >= 500) {
|
||||||
|
console.error('Server error:', response.statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle specific status codes
|
||||||
|
switch (response.statusCode) {
|
||||||
|
case 200:
|
||||||
|
console.log('OK');
|
||||||
|
break;
|
||||||
|
case 201:
|
||||||
|
console.log('Created');
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
console.error('Unauthorized');
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
console.error('Not found');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log('Status:', response.statusCode);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `response.statusText`
|
||||||
|
|
||||||
|
**Type:** `string`
|
||||||
|
**Description:** HTTP status text ("OK", "Not Found", etc.)
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
console.log('Response:', response.statusCode, response.statusText);
|
||||||
|
// Output: "Response: 200 OK"
|
||||||
|
|
||||||
|
if (response.statusText === "OK") {
|
||||||
|
// Process successful response
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `response.responseTime`
|
||||||
|
|
||||||
|
**Type:** `number`
|
||||||
|
**Description:** Response time in milliseconds
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
console.log('Response took', response.responseTime, 'ms');
|
||||||
|
|
||||||
|
if (response.responseTime > 1000) {
|
||||||
|
console.warn('Slow response:', response.responseTime, 'ms');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store for monitoring
|
||||||
|
roster.setVariable('last_response_time', response.responseTime.toString());
|
||||||
|
```
|
||||||
|
|
||||||
|
## Roster API
|
||||||
|
|
||||||
|
**Available in:** Both preprocessing and postprocessing scripts
|
||||||
|
**Namespace:** `roster`
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
#### `roster.getVariable(name)`
|
||||||
|
|
||||||
|
**Available in:** Preprocessing scripts only
|
||||||
|
**Returns:** `string` or `undefined`
|
||||||
|
**Description:** Get variable value from selected environment
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `name` (string): Variable name
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Get variable
|
||||||
|
const apiKey = roster.getVariable('api_key');
|
||||||
|
if (apiKey) {
|
||||||
|
request.headers['X-API-Key'] = apiKey;
|
||||||
|
} else {
|
||||||
|
console.error('API key not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get with default value
|
||||||
|
const timeout = roster.getVariable('timeout') || '30';
|
||||||
|
console.log('Using timeout:', timeout);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important Notes:**
|
||||||
|
- Returns `undefined` if variable doesn't exist
|
||||||
|
- Gets value from currently selected environment
|
||||||
|
- Can access both regular and [[Sensitive-Variables|sensitive variables]]
|
||||||
|
- Sensitive variable values are automatically decrypted from keyring
|
||||||
|
|
||||||
|
#### `roster.setVariable(name, value)`
|
||||||
|
|
||||||
|
**Available in:** Both preprocessing and postprocessing scripts
|
||||||
|
**Returns:** `undefined`
|
||||||
|
**Description:** Set or update variable in selected environment
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `name` (string): Variable name (must match `/^\w+$/`)
|
||||||
|
- `value` (string): Variable value
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Set variable
|
||||||
|
roster.setVariable('user_id', '12345');
|
||||||
|
console.log('Saved user ID');
|
||||||
|
|
||||||
|
// Update existing variable
|
||||||
|
const token = data.access_token;
|
||||||
|
roster.setVariable('auth_token', token);
|
||||||
|
|
||||||
|
// Create new variable (auto-created if doesn't exist)
|
||||||
|
roster.setVariable('session_id', generateSessionId());
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important Notes:**
|
||||||
|
- Creates variable if it doesn't exist
|
||||||
|
- Updates value in currently selected environment
|
||||||
|
- Variable name must be alphanumeric + underscore
|
||||||
|
- If variable is marked as sensitive, value goes to keyring automatically
|
||||||
|
- Value is converted to string
|
||||||
|
|
||||||
|
#### `roster.setVariables(object)`
|
||||||
|
|
||||||
|
**Available in:** Both preprocessing and postprocessing scripts
|
||||||
|
**Returns:** `undefined`
|
||||||
|
**Description:** Set or update multiple variables at once (batch operation)
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `object` (object): Key-value pairs of variable names and values
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
// Set multiple variables
|
||||||
|
roster.setVariables({
|
||||||
|
user_id: data.user.id,
|
||||||
|
user_name: data.user.name,
|
||||||
|
user_email: data.user.email,
|
||||||
|
session_id: data.session_id
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extract response data
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
roster.setVariables({
|
||||||
|
access_token: data.access_token,
|
||||||
|
refresh_token: data.refresh_token,
|
||||||
|
expires_at: data.expires_at
|
||||||
|
});
|
||||||
|
console.log('Saved authentication tokens');
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important Notes:**
|
||||||
|
- All variables updated in single operation
|
||||||
|
- More efficient than multiple `setVariable()` calls
|
||||||
|
- Same validation rules as `setVariable()`
|
||||||
|
- Sensitive variables automatically routed to keyring
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
#### `roster.project.name`
|
||||||
|
|
||||||
|
**Available in:** Preprocessing scripts only
|
||||||
|
**Type:** `string`
|
||||||
|
**Description:** Current project name
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
const projectName = roster.project.name;
|
||||||
|
console.log('Project:', projectName);
|
||||||
|
|
||||||
|
// Add project name to request
|
||||||
|
request.headers['X-Project'] = projectName;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `roster.project.environments`
|
||||||
|
|
||||||
|
**Available in:** Preprocessing scripts only
|
||||||
|
**Type:** `string[]` (array of strings)
|
||||||
|
**Description:** Array of environment names in current project
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
const envs = roster.project.environments;
|
||||||
|
console.log('Available environments:', envs.join(', '));
|
||||||
|
// Output: "Available environments: Production, Staging, Development"
|
||||||
|
|
||||||
|
// Check if environment exists
|
||||||
|
if (envs.includes('Production')) {
|
||||||
|
console.log('Production environment available');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log count
|
||||||
|
console.log('Environment count:', envs.length);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Console API
|
||||||
|
|
||||||
|
**Available in:** Both preprocessing and postprocessing scripts
|
||||||
|
**Namespace:** `console`
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
#### `console.log(...args)`
|
||||||
|
|
||||||
|
**Returns:** `undefined`
|
||||||
|
**Description:** Print message to script output
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
console.log('Simple message');
|
||||||
|
console.log('User ID:', userId);
|
||||||
|
console.log('Request sent to', request.url);
|
||||||
|
console.log('Response status:', response.statusCode, response.statusText);
|
||||||
|
|
||||||
|
// Multiple arguments
|
||||||
|
const name = 'John';
|
||||||
|
const age = 30;
|
||||||
|
console.log('User:', name, 'Age:', age);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output location:**
|
||||||
|
- Preprocessing: "Preprocessing" tab in request panel
|
||||||
|
- Postprocessing: "Postprocessing" tab in request panel
|
||||||
|
|
||||||
|
#### `console.error(...args)`
|
||||||
|
|
||||||
|
**Returns:** `undefined`
|
||||||
|
**Description:** Print error message to script output
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```javascript
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
console.error('Request failed with status:', response.statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.access_token) {
|
||||||
|
console.error('No access token in response');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('JSON parse error:', e.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Visual difference:**
|
||||||
|
- May be styled differently than `console.log()` in output
|
||||||
|
- Indicates errors or warnings
|
||||||
|
|
||||||
|
## Built-in JavaScript Objects
|
||||||
|
|
||||||
|
Standard JavaScript objects available in GJS:
|
||||||
|
|
||||||
|
### Date
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Current timestamp
|
||||||
|
const now = new Date();
|
||||||
|
console.log('Current time:', now.toISOString());
|
||||||
|
|
||||||
|
// Unix timestamp
|
||||||
|
const timestamp = Date.now();
|
||||||
|
console.log('Timestamp:', timestamp);
|
||||||
|
|
||||||
|
// Date arithmetic
|
||||||
|
const expiresAt = new Date(Date.now() + 3600000); // +1 hour
|
||||||
|
roster.setVariable('token_expires', expiresAt.toISOString());
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Parse JSON
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
console.log('Parsed data:', data.name);
|
||||||
|
|
||||||
|
// Stringify JSON
|
||||||
|
const body = { name: "John", age: 30 };
|
||||||
|
request.body = JSON.stringify(body);
|
||||||
|
|
||||||
|
// Pretty print
|
||||||
|
request.body = JSON.stringify(body, null, 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Math
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Random number
|
||||||
|
const requestId = Math.floor(Math.random() * 1000000);
|
||||||
|
roster.setVariable('request_id', requestId.toString());
|
||||||
|
|
||||||
|
// Rounding
|
||||||
|
const responseTimeSeconds = Math.round(response.responseTime / 1000);
|
||||||
|
console.log('Response time:', responseTimeSeconds, 'seconds');
|
||||||
|
```
|
||||||
|
|
||||||
|
### String
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// String manipulation
|
||||||
|
const url = request.url.replace('http://', 'https://');
|
||||||
|
const uppercase = data.name.toUpperCase();
|
||||||
|
const trimmed = data.description.trim();
|
||||||
|
|
||||||
|
// String methods
|
||||||
|
if (response.body.includes('error')) {
|
||||||
|
console.error('Response contains error');
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = request.url.split('/');
|
||||||
|
const lastPart = parts[parts.length - 1];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Array
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Array methods
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
const itemIds = data.items.map(item => item.id);
|
||||||
|
console.log('Item IDs:', itemIds.join(', '));
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
const active = data.items.filter(item => item.active);
|
||||||
|
console.log('Active items:', active.length);
|
||||||
|
|
||||||
|
// Find
|
||||||
|
const firstItem = data.items.find(item => item.id === '123');
|
||||||
|
if (firstItem) {
|
||||||
|
console.log('Found item:', firstItem.name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Object
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Object methods
|
||||||
|
const headers = Object.keys(response.headers);
|
||||||
|
console.log('Header count:', headers.length);
|
||||||
|
|
||||||
|
// Merge objects
|
||||||
|
const defaults = { timeout: 30, retries: 3 };
|
||||||
|
const config = Object.assign({}, defaults, userConfig);
|
||||||
|
|
||||||
|
// Check property
|
||||||
|
if (data.hasOwnProperty('access_token')) {
|
||||||
|
roster.setVariable('auth_token', data.access_token);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
Scripts should handle errors gracefully:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Try-catch for parsing
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
roster.setVariable('user_id', data.user.id);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse JSON:', e.message);
|
||||||
|
console.error('Response body:', response.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check before accessing
|
||||||
|
if (data && data.user && data.user.id) {
|
||||||
|
roster.setVariable('user_id', data.user.id);
|
||||||
|
} else {
|
||||||
|
console.error('Invalid response structure');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate response status
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
// Process data
|
||||||
|
} else {
|
||||||
|
console.error('Request failed:', response.statusCode);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
### No Asynchronous Operations
|
||||||
|
|
||||||
|
- No `setTimeout` / `setInterval`
|
||||||
|
- No `Promise` / `async` / `await`
|
||||||
|
- No `fetch()` / `XMLHttpRequest`
|
||||||
|
- Scripts execute synchronously
|
||||||
|
|
||||||
|
### No External Libraries
|
||||||
|
|
||||||
|
- Cannot import npm packages
|
||||||
|
- Cannot `require()` external modules
|
||||||
|
- Only built-in JavaScript objects available
|
||||||
|
|
||||||
|
### No File System Access
|
||||||
|
|
||||||
|
- Cannot read/write files
|
||||||
|
- Cannot execute shell commands
|
||||||
|
- Cannot access environment variables (use Roster variables instead)
|
||||||
|
|
||||||
|
### No Network Access
|
||||||
|
|
||||||
|
- Cannot make additional HTTP requests
|
||||||
|
- Use Roster's request system instead
|
||||||
|
|
||||||
|
## Type Reference
|
||||||
|
|
||||||
|
### Variable Name Pattern
|
||||||
|
|
||||||
|
Variable names must match: `/^\w+$/`
|
||||||
|
|
||||||
|
Valid:
|
||||||
|
- `api_key`
|
||||||
|
- `user_id`
|
||||||
|
- `access_token`
|
||||||
|
- `BASE_URL`
|
||||||
|
- `token123`
|
||||||
|
|
||||||
|
Invalid:
|
||||||
|
- `api-key` (hyphen not allowed)
|
||||||
|
- `api.key` (dot not allowed)
|
||||||
|
- `api key` (space not allowed)
|
||||||
|
- `@token` (special character)
|
||||||
|
|
||||||
|
### Type Conversions
|
||||||
|
|
||||||
|
Variables are always stored as strings:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Numbers must be converted
|
||||||
|
roster.setVariable('count', data.count.toString());
|
||||||
|
|
||||||
|
// Read as number
|
||||||
|
const count = parseInt(roster.getVariable('count'), 10);
|
||||||
|
|
||||||
|
// Booleans must be converted
|
||||||
|
roster.setVariable('is_active', data.active.toString());
|
||||||
|
|
||||||
|
// Read as boolean
|
||||||
|
const isActive = roster.getVariable('is_active') === 'true';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [[Scripts]] - Practical examples and workflows
|
||||||
|
- [[Variables]] - Learn about environment variables
|
||||||
|
- [[Sensitive-Variables]] - Secure credential storage
|
||||||
260
FAQ.md
Normal file
260
FAQ.md
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
# Frequently Asked Questions
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
### What is Roster?
|
||||||
|
|
||||||
|
Roster is a native GNOME HTTP client for testing and debugging APIs. It provides a clean interface for sending HTTP requests, viewing responses, and automating workflows.
|
||||||
|
|
||||||
|
### Is Roster free?
|
||||||
|
|
||||||
|
Yes! Roster is free and open-source software licensed under GPL-3.0-or-later.
|
||||||
|
|
||||||
|
### What platforms does Roster support?
|
||||||
|
|
||||||
|
Roster is designed for the GNOME desktop environment on Linux. It works on any Linux distribution with GNOME 40+.
|
||||||
|
|
||||||
|
### Can I use Roster on Windows or macOS?
|
||||||
|
|
||||||
|
Roster is specifically built for GNOME/Linux and is not currently available for Windows or macOS.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### How do I install Roster?
|
||||||
|
|
||||||
|
See [[Installation]] for complete instructions. You can:
|
||||||
|
- Build from source
|
||||||
|
- Install via Flatpak
|
||||||
|
- Use GNOME Builder
|
||||||
|
|
||||||
|
### Will Roster be on Flathub?
|
||||||
|
|
||||||
|
Support for Flathub is planned for future releases.
|
||||||
|
|
||||||
|
### What dependencies does Roster need?
|
||||||
|
|
||||||
|
Runtime: GTK 4, libadwaita 1, Python 3, libsoup3, libsecret, GJS
|
||||||
|
|
||||||
|
See [[Installation]] for complete dependency list.
|
||||||
|
|
||||||
|
## Variables and Environments
|
||||||
|
|
||||||
|
### What's the difference between regular and sensitive variables?
|
||||||
|
|
||||||
|
**Regular variables** are stored in plain text JSON files. Use for non-sensitive data like URLs.
|
||||||
|
|
||||||
|
**Sensitive variables** are encrypted and stored in GNOME Keyring. Use for API keys, passwords, and tokens.
|
||||||
|
|
||||||
|
See [[Sensitive-Variables]] for details.
|
||||||
|
|
||||||
|
### Can I use variables in the request body?
|
||||||
|
|
||||||
|
Yes! Use `{{variable_name}}` syntax in:
|
||||||
|
- URL
|
||||||
|
- Headers
|
||||||
|
- Request body
|
||||||
|
|
||||||
|
### How do I switch between environments?
|
||||||
|
|
||||||
|
Use the environment dropdown at the top of the request panel. Switching environments updates all variable values.
|
||||||
|
|
||||||
|
### Can variables from one project be used in another?
|
||||||
|
|
||||||
|
No. Variables are scoped to projects and cannot be shared between projects.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
### Is it safe to store API keys in Roster?
|
||||||
|
|
||||||
|
**If you use sensitive variables: Yes.**
|
||||||
|
|
||||||
|
Mark variables as sensitive (click the lock icon), and values are encrypted in GNOME Keyring.
|
||||||
|
|
||||||
|
**If you use regular variables: No.**
|
||||||
|
|
||||||
|
Regular variables are stored in plain text. Always mark secrets as sensitive!
|
||||||
|
|
||||||
|
### Where are my secrets stored?
|
||||||
|
|
||||||
|
Sensitive variables are stored in GNOME Keyring at:
|
||||||
|
- Native: `~/.local/share/keyrings/`
|
||||||
|
- Encrypted with your login password
|
||||||
|
- Same security as browser passwords, WiFi credentials
|
||||||
|
|
||||||
|
### Can I view my keyring secrets?
|
||||||
|
|
||||||
|
Yes! Open "Passwords and Keys" application (Seahorse), navigate to "Login" keyring, and look for entries starting with "Roster:".
|
||||||
|
|
||||||
|
### What happens if I forget to mark a variable as sensitive?
|
||||||
|
|
||||||
|
You can click the lock icon at any time to mark it as sensitive. Values will be moved from JSON to keyring automatically.
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
### What language do scripts use?
|
||||||
|
|
||||||
|
JavaScript (ES5+), executed via GJS (GNOME JavaScript runtime).
|
||||||
|
|
||||||
|
### Can I use npm packages in scripts?
|
||||||
|
|
||||||
|
No. Scripts run in a sandboxed environment without access to external libraries or npm packages.
|
||||||
|
|
||||||
|
### Can scripts access the file system?
|
||||||
|
|
||||||
|
No. Scripts cannot read/write files, execute shell commands, or access system resources.
|
||||||
|
|
||||||
|
### Why can't I use async/await?
|
||||||
|
|
||||||
|
Scripts execute synchronously. No async operations (setTimeout, Promises, async/await, fetch) are available.
|
||||||
|
|
||||||
|
### Can I make HTTP requests from scripts?
|
||||||
|
|
||||||
|
No. Use Roster's request system and chain requests using variables instead.
|
||||||
|
|
||||||
|
See [[Scripts]] for complete documentation.
|
||||||
|
|
||||||
|
## Requests and Responses
|
||||||
|
|
||||||
|
### Where is request history stored?
|
||||||
|
|
||||||
|
**Native:** `~/.local/share/cz.bugsy.roster/session.json`
|
||||||
|
**Flatpak:** `~/.var/app/cz.bugsy.roster/data/cz.bugsy.roster/session.json`
|
||||||
|
|
||||||
|
### How long is history kept?
|
||||||
|
|
||||||
|
History persists across sessions until you clear it manually.
|
||||||
|
|
||||||
|
### Can I export requests?
|
||||||
|
|
||||||
|
Yes! Click the export button and choose a format:
|
||||||
|
- cURL
|
||||||
|
- More formats may be added in future versions
|
||||||
|
|
||||||
|
### Does Roster support file uploads?
|
||||||
|
|
||||||
|
Multipart form uploads are not currently supported. Planned for future releases.
|
||||||
|
|
||||||
|
### Can I test WebSocket connections?
|
||||||
|
|
||||||
|
WebSocket support is not currently available.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Roster won't start
|
||||||
|
|
||||||
|
**Check dependencies:**
|
||||||
|
```bash
|
||||||
|
# Verify GTK 4 and libadwaita are installed
|
||||||
|
pkg-config --modversion gtk4 libadwaita-1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Check logs:**
|
||||||
|
```bash
|
||||||
|
# Native
|
||||||
|
roster
|
||||||
|
|
||||||
|
# Flatpak
|
||||||
|
flatpak run cz.bugsy.roster
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cannot access GNOME Keyring
|
||||||
|
|
||||||
|
**Ensure keyring is unlocked:**
|
||||||
|
1. Open "Passwords and Keys" (Seahorse)
|
||||||
|
2. Right-click "Login" keyring
|
||||||
|
3. Select "Unlock"
|
||||||
|
|
||||||
|
**For Flatpak, check permissions:**
|
||||||
|
```bash
|
||||||
|
flatpak info --show-permissions cz.bugsy.roster
|
||||||
|
# Should include: --talk-name=org.freedesktop.secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables not substituting
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
1. Environment is selected (dropdown at top of request)
|
||||||
|
2. Variable names match exactly (case-sensitive)
|
||||||
|
3. Syntax is correct: `{{variable_name}}`
|
||||||
|
4. Variable is defined in selected environment
|
||||||
|
|
||||||
|
### Scripts not executing
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
1. Request is saved (scripts only work on saved requests)
|
||||||
|
2. Script has no syntax errors
|
||||||
|
3. Check script output tabs for errors
|
||||||
|
4. GJS (gjs package) is installed
|
||||||
|
|
||||||
|
### Request failing with SSL errors
|
||||||
|
|
||||||
|
**For self-signed certificates:**
|
||||||
|
|
||||||
|
Roster uses system SSL certificates. Add your certificate to the system trust store or use development environments without SSL validation.
|
||||||
|
|
||||||
|
## Data and Privacy
|
||||||
|
|
||||||
|
### Does Roster collect any data?
|
||||||
|
|
||||||
|
No. Roster does not collect, transmit, or share any data. All information stays on your local machine.
|
||||||
|
|
||||||
|
### Can I backup my projects?
|
||||||
|
|
||||||
|
Yes! Backup these files:
|
||||||
|
- `~/.local/share/cz.bugsy.roster/requests.json` (projects and variables)
|
||||||
|
- `~/.local/share/keyrings/` (sensitive variables)
|
||||||
|
|
||||||
|
### How do I reset Roster?
|
||||||
|
|
||||||
|
Delete the data directory:
|
||||||
|
```bash
|
||||||
|
# Native
|
||||||
|
rm -rf ~/.local/share/cz.bugsy.roster/
|
||||||
|
|
||||||
|
# Flatpak
|
||||||
|
rm -rf ~/.var/app/cz.bugsy.roster/data/cz.bugsy.roster/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warning:** This deletes all projects, requests, and history!
|
||||||
|
|
||||||
|
Sensitive variables in keyring must be deleted separately via Seahorse.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
### How can I contribute?
|
||||||
|
|
||||||
|
Contributions welcome! See [[Contributing]] for guidelines.
|
||||||
|
|
||||||
|
### Where do I report bugs?
|
||||||
|
|
||||||
|
Report issues at: https://git.bugsy.cz/beval/roster/issues
|
||||||
|
|
||||||
|
### Can I request features?
|
||||||
|
|
||||||
|
Yes! Open an issue with the "enhancement" label.
|
||||||
|
|
||||||
|
## Comparison
|
||||||
|
|
||||||
|
### How is Roster different from Postman?
|
||||||
|
|
||||||
|
- **Roster**: Native GNOME app, lightweight, open-source, Linux-only
|
||||||
|
- **Postman**: Cross-platform, Electron-based, cloud sync, team features
|
||||||
|
|
||||||
|
Roster focuses on being a simple, fast, native GNOME experience.
|
||||||
|
|
||||||
|
### How is Roster different from Insomnia?
|
||||||
|
|
||||||
|
Similar to Postman comparison. Roster is native GNOME with no cloud dependencies.
|
||||||
|
|
||||||
|
### How is Roster different from HTTPie?
|
||||||
|
|
||||||
|
- **Roster**: GUI application with project management
|
||||||
|
- **HTTPie**: Command-line tool
|
||||||
|
|
||||||
|
Roster provides a visual interface while HTTPie is CLI-focused.
|
||||||
|
|
||||||
|
## Still Have Questions?
|
||||||
|
|
||||||
|
- Check the [[Home|Wiki]] for more documentation
|
||||||
|
- Open an issue: https://git.bugsy.cz/beval/roster/issues
|
||||||
|
- Read the source: https://git.bugsy.cz/beval/roster
|
||||||
245
Getting-Started.md
Normal file
245
Getting-Started.md
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
# Getting Started
|
||||||
|
|
||||||
|
This guide walks you through sending your first HTTP request with Roster.
|
||||||
|
|
||||||
|
## Launch Roster
|
||||||
|
|
||||||
|
After [[Installation]], launch Roster from:
|
||||||
|
- Your application menu (search for "Roster")
|
||||||
|
- Command line: `roster` (or `flatpak run cz.bugsy.roster` for Flatpak)
|
||||||
|
|
||||||
|
## Your First Request
|
||||||
|
|
||||||
|
### Step 1: Create a Project
|
||||||
|
|
||||||
|
Projects help organize related requests (e.g., "GitHub API", "My App API").
|
||||||
|
|
||||||
|
1. Click the **hamburger menu** (three lines) in the top-left
|
||||||
|
2. Select **"New Project"**
|
||||||
|
3. Enter a name: `My First Project`
|
||||||
|
4. Click **"Create"**
|
||||||
|
|
||||||
|
### Step 2: Create a Request
|
||||||
|
|
||||||
|
1. Click the **"+"** button in the header bar
|
||||||
|
2. Or: **Ctrl+T** keyboard shortcut
|
||||||
|
|
||||||
|
A new request tab appears with default values.
|
||||||
|
|
||||||
|
### Step 3: Configure the Request
|
||||||
|
|
||||||
|
**Set the URL:**
|
||||||
|
```
|
||||||
|
https://api.github.com/users/octocat
|
||||||
|
```
|
||||||
|
|
||||||
|
**Set the Method:**
|
||||||
|
- Use the dropdown menu
|
||||||
|
- Default is `GET` (perfect for this example)
|
||||||
|
|
||||||
|
**Add Headers (Optional):**
|
||||||
|
1. Click the **"Headers"** tab
|
||||||
|
2. Add a header:
|
||||||
|
- Key: `User-Agent`
|
||||||
|
- Value: `Roster/0.5.0`
|
||||||
|
|
||||||
|
### Step 4: Send the Request
|
||||||
|
|
||||||
|
Click the **"Send"** button (or press **Ctrl+Return**)
|
||||||
|
|
||||||
|
### Step 5: View the Response
|
||||||
|
|
||||||
|
The response appears in the right panel:
|
||||||
|
|
||||||
|
**Status Line:**
|
||||||
|
```
|
||||||
|
200 OK (123 ms, 1.2 KB)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response Headers:**
|
||||||
|
Click the **"Headers"** dropdown to view all response headers.
|
||||||
|
|
||||||
|
**Response Body:**
|
||||||
|
The JSON response from GitHub API showing user information.
|
||||||
|
|
||||||
|
## Saving Requests
|
||||||
|
|
||||||
|
### Save for Later
|
||||||
|
|
||||||
|
1. Click the **"Save"** button in the header
|
||||||
|
2. Enter a name: `Get GitHub User`
|
||||||
|
3. Click **"Save"**
|
||||||
|
|
||||||
|
The request is now saved to your project.
|
||||||
|
|
||||||
|
### Access Saved Requests
|
||||||
|
|
||||||
|
1. Click the **hamburger menu**
|
||||||
|
2. Your project shows saved requests
|
||||||
|
3. Click a request to open it in a new tab
|
||||||
|
|
||||||
|
## Request History
|
||||||
|
|
||||||
|
Every request you send is automatically saved to history.
|
||||||
|
|
||||||
|
**View History:**
|
||||||
|
1. Click the **"History"** button in the header bar
|
||||||
|
2. Browse past requests
|
||||||
|
3. Click any entry to open it in a new tab
|
||||||
|
|
||||||
|
**History includes:**
|
||||||
|
- Request details (URL, method, headers, body)
|
||||||
|
- Response details (status, headers, body, timing)
|
||||||
|
- Timestamp
|
||||||
|
|
||||||
|
## Working with Tabs
|
||||||
|
|
||||||
|
### Multiple Tabs
|
||||||
|
|
||||||
|
Open multiple requests simultaneously:
|
||||||
|
- **Ctrl+T** - New request tab
|
||||||
|
- **Ctrl+W** - Close current tab
|
||||||
|
- **Ctrl+Tab** / **Ctrl+Shift+Tab** - Switch between tabs
|
||||||
|
|
||||||
|
### Modified Indicator
|
||||||
|
|
||||||
|
Unsaved changes are marked with a dot (•) on the tab label.
|
||||||
|
|
||||||
|
## Next Example: POST Request
|
||||||
|
|
||||||
|
Let's send some data to an API.
|
||||||
|
|
||||||
|
### Step 1: New Request
|
||||||
|
|
||||||
|
Create a new request tab (**Ctrl+T**)
|
||||||
|
|
||||||
|
### Step 2: Configure POST Request
|
||||||
|
|
||||||
|
**URL:**
|
||||||
|
```
|
||||||
|
https://httpbin.org/post
|
||||||
|
```
|
||||||
|
|
||||||
|
**Method:**
|
||||||
|
```
|
||||||
|
POST
|
||||||
|
```
|
||||||
|
|
||||||
|
**Headers:**
|
||||||
|
```
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
1. Click the **"Body"** tab
|
||||||
|
2. Select **"JSON"** syntax highlighting
|
||||||
|
3. Enter JSON data:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Test User",
|
||||||
|
"email": "test@example.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Send and View
|
||||||
|
|
||||||
|
Click **"Send"** and view the response. httpbin.org echoes back your request data.
|
||||||
|
|
||||||
|
## Common Request Types
|
||||||
|
|
||||||
|
### GET Request
|
||||||
|
```
|
||||||
|
Method: GET
|
||||||
|
URL: https://api.example.com/users
|
||||||
|
Headers: (optional)
|
||||||
|
Body: (none)
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST Request
|
||||||
|
```
|
||||||
|
Method: POST
|
||||||
|
URL: https://api.example.com/users
|
||||||
|
Headers: Content-Type: application/json
|
||||||
|
Body: {"name": "John", "email": "john@example.com"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### PUT Request
|
||||||
|
```
|
||||||
|
Method: PUT
|
||||||
|
URL: https://api.example.com/users/123
|
||||||
|
Headers: Content-Type: application/json
|
||||||
|
Body: {"name": "John Updated"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DELETE Request
|
||||||
|
```
|
||||||
|
Method: DELETE
|
||||||
|
URL: https://api.example.com/users/123
|
||||||
|
Headers: (optional)
|
||||||
|
Body: (none)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Response Features
|
||||||
|
|
||||||
|
### Syntax Highlighting
|
||||||
|
|
||||||
|
Roster automatically detects and highlights:
|
||||||
|
- **JSON** responses
|
||||||
|
- **XML** responses
|
||||||
|
- **HTML** responses
|
||||||
|
|
||||||
|
### Response Timing
|
||||||
|
|
||||||
|
View how long the request took:
|
||||||
|
```
|
||||||
|
200 OK (1.23 seconds, 5.4 KB)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Response Size
|
||||||
|
|
||||||
|
The status line shows the total response size including headers.
|
||||||
|
|
||||||
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
|
Essential shortcuts to speed up your workflow:
|
||||||
|
|
||||||
|
| Action | Shortcut |
|
||||||
|
|--------|----------|
|
||||||
|
| New request | **Ctrl+T** |
|
||||||
|
| Send request | **Ctrl+Return** |
|
||||||
|
| Close tab | **Ctrl+W** |
|
||||||
|
| Save request | **Ctrl+S** |
|
||||||
|
| Switch tabs | **Ctrl+Tab** |
|
||||||
|
| Quit | **Ctrl+Q** |
|
||||||
|
|
||||||
|
See [[Keyboard-Shortcuts]] for the complete list.
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
Now that you know the basics, explore more advanced features:
|
||||||
|
|
||||||
|
- [[Projects-and-Environments]] - Organize requests and manage environments
|
||||||
|
- [[Variables]] - Use variables to avoid repetition
|
||||||
|
- [[Sensitive-Variables]] - Store API keys securely
|
||||||
|
- [[Scripts]] - Automate workflows with JavaScript
|
||||||
|
- [[Export]] - Export requests to cURL and other formats
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
**Tip 1: Use httpbin.org for testing**
|
||||||
|
- `https://httpbin.org/get` - Test GET requests
|
||||||
|
- `https://httpbin.org/post` - Test POST requests
|
||||||
|
- `https://httpbin.org/headers` - See your request headers
|
||||||
|
- `https://httpbin.org/delay/3` - Test timeouts
|
||||||
|
|
||||||
|
**Tip 2: Save frequently used requests**
|
||||||
|
- Save requests to projects for quick access
|
||||||
|
- Use descriptive names: "Login", "Get User Profile", etc.
|
||||||
|
|
||||||
|
**Tip 3: Use syntax highlighting**
|
||||||
|
- Select JSON/XML/RAW in the body dropdown
|
||||||
|
- Makes reading requests and responses much easier
|
||||||
|
|
||||||
|
**Tip 4: Check the history**
|
||||||
|
- History persists across sessions
|
||||||
|
- Great for debugging or comparing responses
|
||||||
114
Home.md
114
Home.md
@ -1 +1,113 @@
|
|||||||
Welcome to the Wiki.
|
# Roster Wiki
|
||||||
|
|
||||||
|
Welcome to the **Roster** documentation! Roster is a modern HTTP client for GNOME, built with GTK 4 and libadwaita.
|
||||||
|
|
||||||
|
## What is Roster?
|
||||||
|
|
||||||
|
Roster is a native GNOME application for testing and debugging HTTP APIs. It provides a clean, intuitive interface for:
|
||||||
|
|
||||||
|
- HTTP Requests - Send GET, POST, PUT, DELETE requests
|
||||||
|
- Custom Headers & Bodies - Full control over request configuration
|
||||||
|
- Response Viewing - View headers, body, status, and timing
|
||||||
|
- Request History - Persistent history with full request/response data
|
||||||
|
- Project Organization - Organize requests into projects
|
||||||
|
- Environment Variables - Manage different environments (dev, staging, prod)
|
||||||
|
- Sensitive Variables - Secure storage of API keys and tokens in GNOME Keyring
|
||||||
|
- JavaScript Scripts - Automate workflows with preprocessing/postprocessing
|
||||||
|
- Export - Export requests to cURL and other formats
|
||||||
|
- Beautiful UI - Native GNOME experience with libadwaita
|
||||||
|
|
||||||
|
## Quick Links
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
- [[Installation]] - How to build and install Roster
|
||||||
|
- [[Getting-Started]] - Your first HTTP request
|
||||||
|
- [[Projects-and-Environments]] - Organize your work
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- [[Variables]] - Use variables in requests
|
||||||
|
- [[Sensitive-Variables]] - Secure storage with GNOME Keyring
|
||||||
|
- [[Scripts]] - Preprocessing and postprocessing automation
|
||||||
|
- [[Export]] - Export requests to other tools
|
||||||
|
- [[History]] - Track and replay requests
|
||||||
|
|
||||||
|
### Reference
|
||||||
|
- [[API-Reference]] - Complete JavaScript API documentation
|
||||||
|
- [[Keyboard-Shortcuts]] - Speed up your workflow
|
||||||
|
- [[FAQ]] - Frequently asked questions
|
||||||
|
|
||||||
|
### Development
|
||||||
|
- [[Contributing]] - How to contribute to Roster
|
||||||
|
- [[Development]] - Developer documentation
|
||||||
|
- [[Architecture]] - Technical overview
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
### Secure Credential Storage
|
||||||
|
|
||||||
|
Store API keys, tokens, and passwords securely in GNOME Keyring with one-click encryption:
|
||||||
|
|
||||||
|
```
|
||||||
|
Variables:
|
||||||
|
base_url (unlocked) → Stored in JSON (plain text)
|
||||||
|
api_key (locked) → Stored in GNOME Keyring (encrypted)
|
||||||
|
```
|
||||||
|
|
||||||
|
Learn more: [[Sensitive-Variables]]
|
||||||
|
|
||||||
|
### Powerful Automation
|
||||||
|
|
||||||
|
Use JavaScript preprocessing and postprocessing scripts to:
|
||||||
|
- Extract authentication tokens from responses
|
||||||
|
- Add dynamic headers (timestamps, signatures)
|
||||||
|
- Chain requests together
|
||||||
|
- Validate responses
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Postprocessing: Extract token from login response
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
roster.setVariable('auth_token', data.access_token);
|
||||||
|
console.log('Logged in successfully!');
|
||||||
|
```
|
||||||
|
|
||||||
|
Learn more: [[Scripts]]
|
||||||
|
|
||||||
|
### Multi-Environment Support
|
||||||
|
|
||||||
|
Manage multiple environments with different variable values:
|
||||||
|
|
||||||
|
| Variable | Production | Development |
|
||||||
|
|----------|-----------|-------------|
|
||||||
|
| base_url | `api.example.com` | `localhost:3000` |
|
||||||
|
| api_key | `prod-key-***` | `dev-key-***` |
|
||||||
|
|
||||||
|
Switch environments with one click - all variables update automatically.
|
||||||
|
|
||||||
|
Learn more: [[Variables]]
|
||||||
|
|
||||||
|
## Platform
|
||||||
|
|
||||||
|
Roster is built specifically for the GNOME desktop using:
|
||||||
|
- **GTK 4** - Modern UI toolkit
|
||||||
|
- **libadwaita** - GNOME design patterns
|
||||||
|
- **libsoup3** - HTTP networking (from GNOME Platform)
|
||||||
|
- **libsecret** - Secure credential storage
|
||||||
|
- **GJS** - JavaScript runtime for scripts
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Roster is free and open-source software licensed under **GPL-3.0-or-later**.
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
- **Issues**: https://git.bugsy.cz/beval/roster/issues
|
||||||
|
- **Source**: https://git.bugsy.cz/beval/roster
|
||||||
|
- **Wiki**: You are here!
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
**New to Roster?** Start with [[Installation]] and [[Getting-Started]]
|
||||||
|
|
||||||
|
**Need to store API keys?** Check out [[Sensitive-Variables]]
|
||||||
|
|
||||||
|
**Want to automate workflows?** Learn about [[Scripts]]
|
||||||
|
|||||||
213
Installation.md
Normal file
213
Installation.md
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
This guide covers how to build and install Roster from source.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
Roster requires the following dependencies:
|
||||||
|
|
||||||
|
### Runtime Dependencies
|
||||||
|
- **GTK 4** (>= 4.0)
|
||||||
|
- **libadwaita 1** (>= 1.0)
|
||||||
|
- **Python 3** (>= 3.8)
|
||||||
|
- **libsoup3** - HTTP client library (provided by GNOME Platform)
|
||||||
|
- **libsecret** - Secure credential storage (provided by GNOME Platform)
|
||||||
|
- **GJS** - GNOME JavaScript runtime for script execution
|
||||||
|
|
||||||
|
### Build Dependencies
|
||||||
|
- **Meson** (>= 1.0.0)
|
||||||
|
- **Ninja**
|
||||||
|
- **pkg-config**
|
||||||
|
- **gettext** - For internationalization
|
||||||
|
- **glib-compile-schemas**
|
||||||
|
- **glib-compile-resources**
|
||||||
|
|
||||||
|
## Installation Methods
|
||||||
|
|
||||||
|
### Method 1: Build from Source (Native)
|
||||||
|
|
||||||
|
This method builds and installs Roster directly on your system.
|
||||||
|
|
||||||
|
#### Step 1: Install Dependencies
|
||||||
|
|
||||||
|
**Fedora:**
|
||||||
|
```bash
|
||||||
|
sudo dnf install meson ninja-build gtk4-devel libadwaita-devel \
|
||||||
|
libsoup3-devel libsecret-devel gjs python3 \
|
||||||
|
gettext desktop-file-utils appstream
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ubuntu/Debian:**
|
||||||
|
```bash
|
||||||
|
sudo apt install meson ninja-build libgtk-4-dev libadwaita-1-dev \
|
||||||
|
libsoup-3.0-dev libsecret-1-dev gjs python3 \
|
||||||
|
gettext desktop-file-utils appstream
|
||||||
|
```
|
||||||
|
|
||||||
|
**Arch Linux:**
|
||||||
|
```bash
|
||||||
|
sudo pacman -S meson ninja gtk4 libadwaita libsoup3 libsecret gjs python3 gettext
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: Clone Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.bugsy.cz/beval/roster.git
|
||||||
|
cd roster
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
meson setup builddir
|
||||||
|
meson compile -C builddir
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 4: Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo meson install -C builddir
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 5: Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
roster
|
||||||
|
```
|
||||||
|
|
||||||
|
Or launch from your application menu.
|
||||||
|
|
||||||
|
### Method 2: Build with Flatpak (Recommended)
|
||||||
|
|
||||||
|
Flatpak provides a sandboxed environment with all dependencies included.
|
||||||
|
|
||||||
|
#### Step 1: Install Flatpak Builder
|
||||||
|
|
||||||
|
**Fedora:**
|
||||||
|
```bash
|
||||||
|
sudo dnf install flatpak-builder
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ubuntu/Debian:**
|
||||||
|
```bash
|
||||||
|
sudo apt install flatpak-builder
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: Add Flathub Remote
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Install GNOME SDK
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak install flathub org.gnome.Platform//49 org.gnome.Sdk//49
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 4: Build Flatpak
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.bugsy.cz/beval/roster.git
|
||||||
|
cd roster
|
||||||
|
flatpak-builder --user --install --force-clean build-dir cz.bugsy.roster.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 5: Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak run cz.bugsy.roster
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method 3: GNOME Builder (For Development)
|
||||||
|
|
||||||
|
GNOME Builder provides an integrated development environment.
|
||||||
|
|
||||||
|
#### Step 1: Install GNOME Builder
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak install flathub org.gnome.Builder
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: Open Project
|
||||||
|
|
||||||
|
1. Launch GNOME Builder
|
||||||
|
2. Click "Clone Repository"
|
||||||
|
3. Enter: `https://git.bugsy.cz/beval/roster.git`
|
||||||
|
4. Click "Clone"
|
||||||
|
|
||||||
|
#### Step 3: Build and Run
|
||||||
|
|
||||||
|
1. Click the "Build" button (hammer icon)
|
||||||
|
2. Click the "Run" button (play icon)
|
||||||
|
|
||||||
|
## Uninstallation
|
||||||
|
|
||||||
|
### Native Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd roster/builddir
|
||||||
|
sudo ninja uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flatpak Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flatpak uninstall cz.bugsy.roster
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Locations
|
||||||
|
|
||||||
|
### Native Installation
|
||||||
|
|
||||||
|
- **Binary**: `/usr/local/bin/roster` (or `/usr/bin/roster`)
|
||||||
|
- **Application data**: `~/.local/share/cz.bugsy.roster/`
|
||||||
|
- **Requests/Projects**: `~/.local/share/cz.bugsy.roster/requests.json`
|
||||||
|
- **Session state**: `~/.local/share/cz.bugsy.roster/session.json`
|
||||||
|
- **Sensitive variables**: GNOME Keyring (encrypted)
|
||||||
|
|
||||||
|
### Flatpak Installation
|
||||||
|
|
||||||
|
- **Binary**: Managed by Flatpak
|
||||||
|
- **Application data**: `~/.var/app/cz.bugsy.roster/data/cz.bugsy.roster/`
|
||||||
|
- **Requests/Projects**: `~/.var/app/cz.bugsy.roster/data/cz.bugsy.roster/requests.json`
|
||||||
|
- **Session state**: `~/.var/app/cz.bugsy.roster/data/cz.bugsy.roster/session.json`
|
||||||
|
- **Sensitive variables**: GNOME Keyring (encrypted)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Build Errors
|
||||||
|
|
||||||
|
**Error: "meson: command not found"**
|
||||||
|
- Install Meson build system (see dependencies above)
|
||||||
|
|
||||||
|
**Error: "Package 'gtk4' not found"**
|
||||||
|
- Install GTK 4 development files (see dependencies above)
|
||||||
|
|
||||||
|
**Error: "Package 'libadwaita-1' not found"**
|
||||||
|
- Install libadwaita development files (see dependencies above)
|
||||||
|
|
||||||
|
### Runtime Errors
|
||||||
|
|
||||||
|
**Error: "Failed to access Secret Service"**
|
||||||
|
- Ensure GNOME Keyring is installed and unlocked
|
||||||
|
- For Flatpak: Check that D-Bus permission is granted
|
||||||
|
|
||||||
|
**Error: "Module 'gi' not found"**
|
||||||
|
- Ensure PyGObject is installed: `sudo dnf install python3-gobject`
|
||||||
|
|
||||||
|
### Flatpak Specific
|
||||||
|
|
||||||
|
**Error: "error: Nothing matches org.gnome.Platform"**
|
||||||
|
- Add Flathub remote: `flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo`
|
||||||
|
- Install GNOME SDK: `flatpak install flathub org.gnome.Platform//49 org.gnome.Sdk//49`
|
||||||
|
|
||||||
|
**Application doesn't have network access**
|
||||||
|
- Check Flatpak permissions: `flatpak info --show-permissions cz.bugsy.roster`
|
||||||
|
- Should include: `--share=network`
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [[Getting-Started]] - Learn how to use Roster
|
||||||
|
- [[Projects-and-Environments]] - Organize your API testing
|
||||||
|
- [[Variables]] - Use variables in requests
|
||||||
55
Keyboard-Shortcuts.md
Normal file
55
Keyboard-Shortcuts.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Keyboard Shortcuts
|
||||||
|
|
||||||
|
Complete list of keyboard shortcuts in Roster.
|
||||||
|
|
||||||
|
## Request Management
|
||||||
|
|
||||||
|
| Action | Shortcut |
|
||||||
|
|--------|----------|
|
||||||
|
| New request tab | **Ctrl+T** |
|
||||||
|
| Close current tab | **Ctrl+W** |
|
||||||
|
| Send request | **Ctrl+Return** |
|
||||||
|
| Save request | **Ctrl+S** |
|
||||||
|
|
||||||
|
## Navigation
|
||||||
|
|
||||||
|
| Action | Shortcut |
|
||||||
|
|--------|----------|
|
||||||
|
| Next tab | **Ctrl+Tab** |
|
||||||
|
| Previous tab | **Ctrl+Shift+Tab** |
|
||||||
|
| Focus URL field | **Ctrl+L** |
|
||||||
|
|
||||||
|
## Application
|
||||||
|
|
||||||
|
| Action | Shortcut |
|
||||||
|
|--------|----------|
|
||||||
|
| Show keyboard shortcuts | **Ctrl+?** |
|
||||||
|
| Quit application | **Ctrl+Q** |
|
||||||
|
|
||||||
|
## Dialog Management
|
||||||
|
|
||||||
|
| Action | Shortcut |
|
||||||
|
|--------|----------|
|
||||||
|
| Close dialog | **Escape** |
|
||||||
|
| Confirm action | **Return** or **Enter** |
|
||||||
|
|
||||||
|
## Text Editing
|
||||||
|
|
||||||
|
Standard text editing shortcuts work in all text fields:
|
||||||
|
|
||||||
|
| Action | Shortcut |
|
||||||
|
|--------|----------|
|
||||||
|
| Select all | **Ctrl+A** |
|
||||||
|
| Copy | **Ctrl+C** |
|
||||||
|
| Cut | **Ctrl+X** |
|
||||||
|
| Paste | **Ctrl+V** |
|
||||||
|
| Undo | **Ctrl+Z** |
|
||||||
|
| Redo | **Ctrl+Shift+Z** |
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
**Quick Send:** After editing request, press **Ctrl+Return** to send immediately without clicking.
|
||||||
|
|
||||||
|
**Fast Tab Switching:** Use **Ctrl+Tab** to cycle through open requests.
|
||||||
|
|
||||||
|
**Save Often:** Press **Ctrl+S** frequently to avoid losing work.
|
||||||
255
Projects-and-Environments.md
Normal file
255
Projects-and-Environments.md
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
# Projects and Environments
|
||||||
|
|
||||||
|
Projects help organize related HTTP requests, while environments allow you to manage different configurations (development, staging, production).
|
||||||
|
|
||||||
|
## Projects
|
||||||
|
|
||||||
|
### What is a Project?
|
||||||
|
|
||||||
|
A project is a container for:
|
||||||
|
- **Saved requests** - Your HTTP requests
|
||||||
|
- **Variables** - Shared variables across requests
|
||||||
|
- **Environments** - Different configurations (dev, prod, etc.)
|
||||||
|
|
||||||
|
Example projects:
|
||||||
|
- "GitHub API"
|
||||||
|
- "My App Backend"
|
||||||
|
- "Payment Integration"
|
||||||
|
- "Authentication Service"
|
||||||
|
|
||||||
|
### Creating a Project
|
||||||
|
|
||||||
|
1. Click the **hamburger menu** (three lines) in top-left
|
||||||
|
2. Select **"New Project"**
|
||||||
|
3. Enter project name
|
||||||
|
4. Click **"Create"**
|
||||||
|
|
||||||
|
A default "Default" environment is automatically created.
|
||||||
|
|
||||||
|
### Accessing Projects
|
||||||
|
|
||||||
|
Projects appear in the sidebar on the left side:
|
||||||
|
- Click a project to expand/collapse
|
||||||
|
- Shows saved requests within the project
|
||||||
|
- Active project highlighted
|
||||||
|
|
||||||
|
### Renaming a Project
|
||||||
|
|
||||||
|
1. Right-click the project in sidebar
|
||||||
|
2. Select **"Rename"**
|
||||||
|
3. Enter new name
|
||||||
|
4. Click **"Save"**
|
||||||
|
|
||||||
|
### Deleting a Project
|
||||||
|
|
||||||
|
1. Right-click the project in sidebar
|
||||||
|
2. Select **"Delete"**
|
||||||
|
3. Confirm deletion
|
||||||
|
|
||||||
|
**Warning:** This deletes all requests, environments, and variables in the project!
|
||||||
|
|
||||||
|
### Changing Project Icon
|
||||||
|
|
||||||
|
1. Right-click the project in sidebar
|
||||||
|
2. Select **"Change Icon"**
|
||||||
|
3. Choose icon from grid
|
||||||
|
4. Icon updates immediately
|
||||||
|
|
||||||
|
## Environments
|
||||||
|
|
||||||
|
### What is an Environment?
|
||||||
|
|
||||||
|
An environment is a set of variable values. Common environments:
|
||||||
|
- **Production** - Live API with real credentials
|
||||||
|
- **Staging** - Pre-production testing
|
||||||
|
- **Development** - Local development server
|
||||||
|
- **Testing** - Automated test environment
|
||||||
|
|
||||||
|
### Managing Environments
|
||||||
|
|
||||||
|
See [[Variables]] for complete environment and variable management documentation.
|
||||||
|
|
||||||
|
**Quick access:**
|
||||||
|
1. Select a project
|
||||||
|
2. Click **"Environments"** button in header bar
|
||||||
|
3. Manage environments and variables in dialog
|
||||||
|
|
||||||
|
### Default Environment
|
||||||
|
|
||||||
|
Each project starts with a "Default" environment. You can:
|
||||||
|
- Rename it
|
||||||
|
- Add more environments
|
||||||
|
- Delete it (if you have at least one other environment)
|
||||||
|
|
||||||
|
## Saved Requests
|
||||||
|
|
||||||
|
### Saving a Request
|
||||||
|
|
||||||
|
1. Configure your request (URL, method, headers, body)
|
||||||
|
2. Click **"Save"** button in header
|
||||||
|
3. Enter request name (e.g., "Get User Profile")
|
||||||
|
4. Click **"Save"**
|
||||||
|
|
||||||
|
Request is now saved to the current project.
|
||||||
|
|
||||||
|
### Opening a Saved Request
|
||||||
|
|
||||||
|
1. Click the hamburger menu
|
||||||
|
2. Navigate to your project
|
||||||
|
3. Click on a saved request
|
||||||
|
4. Request opens in a new tab
|
||||||
|
|
||||||
|
### Editing a Saved Request
|
||||||
|
|
||||||
|
1. Open the request
|
||||||
|
2. Make changes
|
||||||
|
3. Click **"Save"** (or Ctrl+S)
|
||||||
|
4. Changes are saved
|
||||||
|
|
||||||
|
**Modified indicator:** Unsaved changes show a dot (•) on the tab label.
|
||||||
|
|
||||||
|
### Deleting a Saved Request
|
||||||
|
|
||||||
|
1. Right-click the request in sidebar
|
||||||
|
2. Select **"Delete"**
|
||||||
|
3. Confirm deletion
|
||||||
|
|
||||||
|
### Attaching Scripts
|
||||||
|
|
||||||
|
See [[Scripts]] for complete documentation.
|
||||||
|
|
||||||
|
1. Save a request first
|
||||||
|
2. Right-click the request in sidebar
|
||||||
|
3. Select **"Edit Scripts"**
|
||||||
|
4. Write preprocessing/postprocessing scripts
|
||||||
|
5. Click **"Save"**
|
||||||
|
|
||||||
|
## Switching Between Projects
|
||||||
|
|
||||||
|
### In Sidebar
|
||||||
|
|
||||||
|
Simply click different projects in the sidebar to view their contents.
|
||||||
|
|
||||||
|
### Request Association
|
||||||
|
|
||||||
|
Each request tab remembers its project:
|
||||||
|
- Variables come from that project's environments
|
||||||
|
- Saving updates that project
|
||||||
|
|
||||||
|
## Organization Tips
|
||||||
|
|
||||||
|
### Group by Service
|
||||||
|
|
||||||
|
Create separate projects for each external API:
|
||||||
|
```
|
||||||
|
Projects:
|
||||||
|
GitHub API
|
||||||
|
- List Repositories
|
||||||
|
- Create Issue
|
||||||
|
- Get User
|
||||||
|
Stripe API
|
||||||
|
- Create Customer
|
||||||
|
- Create Payment
|
||||||
|
- List Charges
|
||||||
|
```
|
||||||
|
|
||||||
|
### Group by Feature
|
||||||
|
|
||||||
|
Create projects for features in your app:
|
||||||
|
```
|
||||||
|
Projects:
|
||||||
|
Authentication
|
||||||
|
- Login
|
||||||
|
- Logout
|
||||||
|
- Refresh Token
|
||||||
|
User Management
|
||||||
|
- Create User
|
||||||
|
- Update Profile
|
||||||
|
- Delete Account
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Descriptive Names
|
||||||
|
|
||||||
|
**Good request names:**
|
||||||
|
- "Login with Email/Password"
|
||||||
|
- "Get User Profile by ID"
|
||||||
|
- "Create Payment Intent (Stripe)"
|
||||||
|
- "Update User Settings"
|
||||||
|
|
||||||
|
**Bad request names:**
|
||||||
|
- "Request 1"
|
||||||
|
- "Test"
|
||||||
|
- "New Request"
|
||||||
|
- "GET"
|
||||||
|
|
||||||
|
## Project Workflow Example
|
||||||
|
|
||||||
|
### Step 1: Create Project
|
||||||
|
|
||||||
|
Create "My API" project
|
||||||
|
|
||||||
|
### Step 2: Add Environments
|
||||||
|
|
||||||
|
Open Environments dialog, add:
|
||||||
|
- Production
|
||||||
|
- Development
|
||||||
|
|
||||||
|
### Step 3: Define Variables
|
||||||
|
|
||||||
|
Add variables:
|
||||||
|
- `base_url`
|
||||||
|
- Production: `https://api.example.com`
|
||||||
|
- Development: `http://localhost:3000`
|
||||||
|
- `api_key` (mark as sensitive)
|
||||||
|
- Production: `prod-key-***`
|
||||||
|
- Development: `dev-key-***`
|
||||||
|
|
||||||
|
### Step 4: Create Requests
|
||||||
|
|
||||||
|
Create and save requests:
|
||||||
|
- "Get Users" - `GET {{base_url}}/users`
|
||||||
|
- "Create User" - `POST {{base_url}}/users`
|
||||||
|
- "Delete User" - `DELETE {{base_url}}/users/{{user_id}}`
|
||||||
|
|
||||||
|
### Step 5: Test Different Environments
|
||||||
|
|
||||||
|
1. Open "Get Users" request
|
||||||
|
2. Select "Development" environment
|
||||||
|
3. Send (hits localhost)
|
||||||
|
4. Select "Production" environment
|
||||||
|
5. Send (hits production API)
|
||||||
|
|
||||||
|
Same request, different targets!
|
||||||
|
|
||||||
|
## Data Storage
|
||||||
|
|
||||||
|
### File Location
|
||||||
|
|
||||||
|
**Native:**
|
||||||
|
```
|
||||||
|
~/.local/share/cz.bugsy.roster/requests.json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Flatpak:**
|
||||||
|
```
|
||||||
|
~/.var/app/cz.bugsy.roster/data/cz.bugsy.roster/requests.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sensitive Variables
|
||||||
|
|
||||||
|
Regular variables stored in JSON.
|
||||||
|
Sensitive variables stored in GNOME Keyring (encrypted).
|
||||||
|
|
||||||
|
See [[Sensitive-Variables]] for details.
|
||||||
|
|
||||||
|
### Backup
|
||||||
|
|
||||||
|
To backup your projects:
|
||||||
|
1. Copy the `requests.json` file
|
||||||
|
2. For sensitive variables: backup your GNOME Keyring (see [[Sensitive-Variables]])
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [[Variables]] - Learn about variables and environments
|
||||||
|
- [[Sensitive-Variables]] - Secure credential storage
|
||||||
|
- [[Scripts]] - Automate workflows
|
||||||
552
Scripts.md
Normal file
552
Scripts.md
Normal file
@ -0,0 +1,552 @@
|
|||||||
|
# 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: Save a Request
|
||||||
|
|
||||||
|
Scripts are attached to saved requests.
|
||||||
|
|
||||||
|
1. Configure your request
|
||||||
|
2. Click **"Save"** button
|
||||||
|
3. Enter request name
|
||||||
|
4. Click **"Save"**
|
||||||
|
|
||||||
|
### Step 2: Open Script Editor
|
||||||
|
|
||||||
|
1. Right-click the saved request in the sidebar
|
||||||
|
2. Select **"Edit Scripts"**
|
||||||
|
3. Script editor dialog opens with two tabs:
|
||||||
|
- **Preprocessing** tab
|
||||||
|
- **Postprocessing** tab
|
||||||
|
|
||||||
|
### Step 3: Write Your Script
|
||||||
|
|
||||||
|
1. Select the appropriate tab
|
||||||
|
2. Write JavaScript code
|
||||||
|
3. Click **"Save"** or **Ctrl+S**
|
||||||
|
4. Close dialog
|
||||||
|
|
||||||
|
### Step 4: 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)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
console.log(message) // Output shown in preprocessing results tab
|
||||||
|
console.error(message) // Error output
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### 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');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 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');
|
||||||
|
} else {
|
||||||
|
console.log('Using development 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);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example 4: Add HMAC Signature
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
console.log(message) // Output shown in postprocessing results tab
|
||||||
|
console.error(message) // Error output
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### 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');
|
||||||
|
} else {
|
||||||
|
console.error('No access token in response');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example 2: Extract Multiple Values
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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
|
||||||
|
|
||||||
|
```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);
|
||||||
|
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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 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:
|
||||||
|
```javascript
|
||||||
|
// 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:
|
||||||
|
```javascript
|
||||||
|
// 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:
|
||||||
|
```javascript
|
||||||
|
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:
|
||||||
|
```javascript
|
||||||
|
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:**
|
||||||
|
```javascript
|
||||||
|
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:**
|
||||||
|
```javascript
|
||||||
|
// 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 you click "Send" on a request with scripts:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Load request from UI
|
||||||
|
2. IF preprocessing script exists:
|
||||||
|
2a. Execute preprocessing script
|
||||||
|
2b. Script can modify request object
|
||||||
|
2c. Script output shown in "Preprocessing" tab
|
||||||
|
3. Apply variable substitution ({{variable_name}})
|
||||||
|
4. Send HTTP request
|
||||||
|
5. Receive response
|
||||||
|
6. IF postprocessing script exists:
|
||||||
|
6a. Execute postprocessing script
|
||||||
|
6b. Script can read response, set variables
|
||||||
|
6c. Script output shown in "Postprocessing" tab
|
||||||
|
7. Display response in UI
|
||||||
|
8. Save to history
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Script Errors
|
||||||
|
|
||||||
|
If a script throws an error:
|
||||||
|
- Error message shown in script results tab
|
||||||
|
- Request still executes (preprocessing) or response still displays (postprocessing)
|
||||||
|
- Variable changes before the error are preserved
|
||||||
|
|
||||||
|
### Example: Safe JSON Parsing
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
roster.setVariable('user_id', data.user.id);
|
||||||
|
console.log('Success');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse JSON:', e.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Keep Scripts Simple
|
||||||
|
|
||||||
|
Scripts should be short and focused:
|
||||||
|
- One clear purpose per script
|
||||||
|
- Avoid complex logic
|
||||||
|
- Use console.log for debugging
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
Always handle potential errors:
|
||||||
|
```javascript
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
// ... process data
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Parse error:', e.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('Request failed:', response.statusText);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variable Naming
|
||||||
|
|
||||||
|
Use clear, descriptive variable names:
|
||||||
|
```javascript
|
||||||
|
// Good
|
||||||
|
roster.setVariable('github_access_token', token);
|
||||||
|
roster.setVariable('user_profile_id', id);
|
||||||
|
|
||||||
|
// Bad
|
||||||
|
roster.setVariable('token', token);
|
||||||
|
roster.setVariable('id', id);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
Use console output to track script execution:
|
||||||
|
```javascript
|
||||||
|
console.log('Starting authentication...');
|
||||||
|
// ... authentication logic
|
||||||
|
console.log('Authentication complete');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sensitive Data
|
||||||
|
|
||||||
|
**Never log sensitive data:**
|
||||||
|
```javascript
|
||||||
|
// BAD - logs the actual token
|
||||||
|
const token = roster.getVariable('api_key');
|
||||||
|
console.log('Token:', token);
|
||||||
|
|
||||||
|
// GOOD - confirms without revealing
|
||||||
|
const token = roster.getVariable('api_key');
|
||||||
|
console.log('Token retrieved');
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 Output
|
||||||
|
|
||||||
|
Liberally use console.log:
|
||||||
|
```javascript
|
||||||
|
console.log('Request URL before:', request.url);
|
||||||
|
// ... modify URL
|
||||||
|
console.log('Request URL after:', request.url);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Script Results
|
||||||
|
|
||||||
|
After sending request:
|
||||||
|
1. Look for "Preprocessing" tab (if preprocessing script exists)
|
||||||
|
2. Look for "Postprocessing" tab (if postprocessing script exists)
|
||||||
|
3. View console output and any errors
|
||||||
|
|
||||||
|
### Test with Simple Scripts
|
||||||
|
|
||||||
|
Start simple and build up:
|
||||||
|
```javascript
|
||||||
|
// Test 1: Verify script runs
|
||||||
|
console.log('Script is running!');
|
||||||
|
|
||||||
|
// Test 2: Verify variable access
|
||||||
|
const baseUrl = roster.getVariable('base_url');
|
||||||
|
console.log('Base URL:', baseUrl);
|
||||||
|
|
||||||
|
// Test 3: Verify request modification
|
||||||
|
request.headers['X-Test'] = 'hello';
|
||||||
|
console.log('Added test header');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [[API-Reference]] - Complete API documentation
|
||||||
|
- [[Variables]] - Learn about environment variables
|
||||||
|
- [[Sensitive-Variables]] - Secure storage for tokens and keys
|
||||||
377
Sensitive-Variables.md
Normal file
377
Sensitive-Variables.md
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
# Sensitive Variables
|
||||||
|
|
||||||
|
Sensitive variables provide secure storage for API keys, passwords, and tokens using GNOME Keyring encryption instead of plain text files.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Regular [[Variables]] are stored in plain text JSON files at `~/.local/share/cz.bugsy.roster/requests.json`. This is fine for non-sensitive data like base URLs or timeout values, but **dangerous for secrets**.
|
||||||
|
|
||||||
|
**Sensitive variables** solve this by storing values encrypted in GNOME Keyring, the same secure storage used by:
|
||||||
|
- Firefox and GNOME Web for passwords
|
||||||
|
- Evolution for email credentials
|
||||||
|
- Network Manager for WiFi passwords
|
||||||
|
- SSH for key passphrases
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
### Storage Comparison
|
||||||
|
|
||||||
|
**Regular Variable (Insecure):**
|
||||||
|
```
|
||||||
|
File: ~/.local/share/cz.bugsy.roster/requests.json
|
||||||
|
Format: Plain text (anyone can read)
|
||||||
|
Content: "api_key": "secret-abc123-visible-to-all"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Sensitive Variable (Secure):**
|
||||||
|
```
|
||||||
|
File: ~/.local/share/cz.bugsy.roster/requests.json
|
||||||
|
Format: Plain text
|
||||||
|
Content: "api_key": "" (empty placeholder)
|
||||||
|
|
||||||
|
Keyring: GNOME Keyring (encrypted)
|
||||||
|
Format: Encrypted with your login password
|
||||||
|
Content: "secret-abc123-visible-to-all" (encrypted at rest)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Step 1: Open Environments Dialog
|
||||||
|
|
||||||
|
1. Select your project from the sidebar
|
||||||
|
2. Click the **"Environments"** button in the header bar
|
||||||
|
3. The variables table appears
|
||||||
|
|
||||||
|
### Step 2: Identify the Lock Icon
|
||||||
|
|
||||||
|
Each variable row has three buttons:
|
||||||
|
- Variable name entry
|
||||||
|
- **Lock icon** (toggle between secure/insecure storage)
|
||||||
|
- Delete button (trash icon)
|
||||||
|
|
||||||
|
### Step 3: Mark Variable as Sensitive
|
||||||
|
|
||||||
|
**Before entering secrets (recommended):**
|
||||||
|
1. Create variable (e.g., `api_key`)
|
||||||
|
2. Click the **lock icon** (appears as unlocked/gray initially)
|
||||||
|
3. Icon changes to locked state (with accent color)
|
||||||
|
4. Variable name becomes bold and colored
|
||||||
|
5. Now enter your secret value
|
||||||
|
|
||||||
|
**After entering secrets (migration):**
|
||||||
|
1. Click the lock icon on existing variable
|
||||||
|
2. Values automatically move from JSON to keyring
|
||||||
|
3. JSON file now contains empty placeholders
|
||||||
|
|
||||||
|
### Step 4: Enter Secret Values
|
||||||
|
|
||||||
|
1. Click in the value entry field
|
||||||
|
2. Type your secret value
|
||||||
|
3. **You'll see bullets (••••••) instead of characters**
|
||||||
|
4. Value automatically saves to GNOME Keyring (encrypted)
|
||||||
|
|
||||||
|
### Step 5: Use in Requests
|
||||||
|
|
||||||
|
Sensitive variables work exactly like regular variables:
|
||||||
|
|
||||||
|
```
|
||||||
|
GET {{base_url}}/users
|
||||||
|
Authorization: Bearer {{api_key}}
|
||||||
|
```
|
||||||
|
|
||||||
|
When you send the request:
|
||||||
|
1. Roster retrieves `api_key` from GNOME Keyring
|
||||||
|
2. Decrypts it using your login password
|
||||||
|
3. Substitutes it into the request
|
||||||
|
4. Sends the request with the real value
|
||||||
|
|
||||||
|
## Visual Indicators
|
||||||
|
|
||||||
|
### Lock Icon States
|
||||||
|
|
||||||
|
**Unlocked (channel-insecure-symbolic):**
|
||||||
|
- Gray/inactive appearance
|
||||||
|
- Variable stored in plain JSON
|
||||||
|
- Tooltip: "Not sensitive (stored in JSON) - Click to mark as sensitive"
|
||||||
|
|
||||||
|
**Locked (channel-secure-symbolic):**
|
||||||
|
- Colored/active appearance (accent color)
|
||||||
|
- Variable stored in encrypted keyring
|
||||||
|
- Tooltip: "Sensitive (stored in keyring) - Click to make non-sensitive"
|
||||||
|
|
||||||
|
### Variable Name Styling
|
||||||
|
|
||||||
|
**Regular variables:**
|
||||||
|
- Normal text color
|
||||||
|
- Normal font weight
|
||||||
|
|
||||||
|
**Sensitive variables:**
|
||||||
|
- Accent color (theme-dependent)
|
||||||
|
- Bold font weight
|
||||||
|
- Easy to identify at a glance
|
||||||
|
|
||||||
|
### Value Entry Fields
|
||||||
|
|
||||||
|
**Regular variables:**
|
||||||
|
- Show typed characters normally
|
||||||
|
- Standard text entry
|
||||||
|
|
||||||
|
**Sensitive variables:**
|
||||||
|
- Show bullets (••••••) like password fields
|
||||||
|
- Entry purpose: PASSWORD
|
||||||
|
- Cannot see the value while typing
|
||||||
|
|
||||||
|
## Viewing Secrets in Keyring
|
||||||
|
|
||||||
|
To verify your secrets are encrypted:
|
||||||
|
|
||||||
|
1. Open **"Passwords and Keys"** application (Seahorse)
|
||||||
|
2. Navigate to **"Login"** keyring
|
||||||
|
3. Look for entries labeled: `Roster: ProjectName/EnvironmentName/VariableName`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
Login Keyring
|
||||||
|
Roster: GitHub API/Production/api_token
|
||||||
|
Roster: GitHub API/Development/api_token
|
||||||
|
Roster: Stripe API/Production/secret_key
|
||||||
|
```
|
||||||
|
|
||||||
|
Click any entry to:
|
||||||
|
- View the secret value (requires authentication)
|
||||||
|
- Edit the value manually
|
||||||
|
- Delete the secret
|
||||||
|
|
||||||
|
## Making Variables Non-Sensitive
|
||||||
|
|
||||||
|
If you marked a variable as sensitive by mistake:
|
||||||
|
|
||||||
|
1. Click the lock icon again
|
||||||
|
2. Icon changes from locked to unlocked
|
||||||
|
3. Values move from keyring back to JSON
|
||||||
|
4. You can now see values in plain text
|
||||||
|
|
||||||
|
**Warning:** Only do this for non-sensitive data! Once moved to JSON, the values are visible to anyone who can read your files.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
### Encryption
|
||||||
|
|
||||||
|
- Values encrypted at rest with your GNOME login password
|
||||||
|
- Uses same encryption as system passwords
|
||||||
|
- No plaintext secrets in file system
|
||||||
|
|
||||||
|
### Auto-Unlock
|
||||||
|
|
||||||
|
- Keyring unlocks automatically when you log in
|
||||||
|
- No need to enter password again
|
||||||
|
- Locked when you log out
|
||||||
|
|
||||||
|
### Access Control
|
||||||
|
|
||||||
|
- Only your user account can access
|
||||||
|
- Protected by OS-level security
|
||||||
|
- Sandboxed apps (Flatpak) require explicit permission
|
||||||
|
|
||||||
|
### Separation
|
||||||
|
|
||||||
|
Roster secrets are stored with a custom schema:
|
||||||
|
- Schema: `cz.bugsy.roster.EnvironmentVariable`
|
||||||
|
- Attributes: `project_id`, `environment_id`, `variable_name`
|
||||||
|
- **Won't clutter your personal passwords**
|
||||||
|
- Easy to identify in Seahorse
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### DO Mark as Sensitive
|
||||||
|
|
||||||
|
- **API keys**: `api_key`, `github_token`, `stripe_key`
|
||||||
|
- **Passwords**: `password`, `db_password`, `admin_pass`
|
||||||
|
- **Tokens**: `bearer_token`, `oauth_token`, `access_token`
|
||||||
|
- **Secrets**: `client_secret`, `api_secret`, `webhook_secret`
|
||||||
|
- **Private keys**: Any cryptographic keys
|
||||||
|
|
||||||
|
### DON'T Mark as Sensitive
|
||||||
|
|
||||||
|
- **URLs**: `base_url`, `api_endpoint`, `webhook_url`
|
||||||
|
- **Configuration**: `timeout`, `max_retries`, `api_version`
|
||||||
|
- **Identifiers**: `env`, `region`, `datacenter`, `tenant_id`
|
||||||
|
- **Non-secret data**: Anything that's OK to be visible
|
||||||
|
|
||||||
|
### Workflow Tips
|
||||||
|
|
||||||
|
**Create variables first, then mark as sensitive:**
|
||||||
|
```
|
||||||
|
1. Add variable "api_key"
|
||||||
|
2. Click lock icon (mark as sensitive)
|
||||||
|
3. Enter value (goes to keyring immediately)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use descriptive names:**
|
||||||
|
```
|
||||||
|
Good: github_personal_token, stripe_secret_key
|
||||||
|
Bad: token1, key, secret
|
||||||
|
```
|
||||||
|
|
||||||
|
**Group related variables:**
|
||||||
|
```
|
||||||
|
base_url (regular)
|
||||||
|
api_key (sensitive)
|
||||||
|
api_secret (sensitive)
|
||||||
|
timeout (regular)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatic Cleanup
|
||||||
|
|
||||||
|
When you delete variables, environments, or projects, Roster automatically cleans up keyring secrets:
|
||||||
|
|
||||||
|
**Delete variable:**
|
||||||
|
- Removed from JSON
|
||||||
|
- All keyring secrets for that variable deleted (across all environments)
|
||||||
|
|
||||||
|
**Delete environment:**
|
||||||
|
- Removed from JSON
|
||||||
|
- All keyring secrets for that environment deleted
|
||||||
|
|
||||||
|
**Delete project:**
|
||||||
|
- Project removed from disk
|
||||||
|
- **All keyring secrets for that project deleted**
|
||||||
|
|
||||||
|
**Rename variable:**
|
||||||
|
- Variable renamed in JSON
|
||||||
|
- All keyring secrets automatically renamed
|
||||||
|
- No data loss
|
||||||
|
|
||||||
|
## Script Integration
|
||||||
|
|
||||||
|
Scripts can access sensitive variables transparently:
|
||||||
|
|
||||||
|
### Reading Sensitive Variables
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Preprocessing script
|
||||||
|
const apiKey = roster.getVariable('api_key'); // Retrieved from keyring
|
||||||
|
request.headers['X-API-Key'] = apiKey;
|
||||||
|
console.log('Using API key'); // DON'T log the actual value!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Writing Sensitive Variables
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Postprocessing script
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
|
||||||
|
// If 'access_token' is marked as sensitive, it goes to keyring
|
||||||
|
roster.setVariable('access_token', data.access_token);
|
||||||
|
console.log('Saved access token to keyring');
|
||||||
|
```
|
||||||
|
|
||||||
|
Scripts don't need to know whether variables are sensitive - storage is handled automatically.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Keyring Not Unlocked
|
||||||
|
|
||||||
|
**Symptom:** Error accessing secrets
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Ensure you're logged into GNOME
|
||||||
|
2. Keyring unlocks automatically on login
|
||||||
|
3. Manual unlock: Open "Passwords and Keys", right-click "Login", select "Unlock"
|
||||||
|
|
||||||
|
### Flatpak Permission Denied
|
||||||
|
|
||||||
|
**Symptom:** Cannot access keyring from Flatpak
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Check `cz.bugsy.roster.json` includes: `--talk-name=org.freedesktop.secrets`
|
||||||
|
2. Rebuild Flatpak with correct permissions
|
||||||
|
3. Verify: `flatpak info --show-permissions cz.bugsy.roster`
|
||||||
|
|
||||||
|
### Cannot View Secret in Seahorse
|
||||||
|
|
||||||
|
**Symptom:** Secret exists but won't display
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Right-click the secret in Seahorse
|
||||||
|
2. Select "Show password"
|
||||||
|
3. Enter your login password when prompted
|
||||||
|
|
||||||
|
### Lost Secrets After Reinstall
|
||||||
|
|
||||||
|
**Symptom:** Secrets missing after reinstalling Roster
|
||||||
|
|
||||||
|
**Keyring persists across installs** - secrets should still be there.
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
1. Open Seahorse
|
||||||
|
2. Look under "Login" keyring
|
||||||
|
3. Search for "Roster:"
|
||||||
|
|
||||||
|
If missing, you'll need to re-enter them.
|
||||||
|
|
||||||
|
## Advanced: Manual Keyring Management
|
||||||
|
|
||||||
|
You can manually manage Roster secrets using Seahorse:
|
||||||
|
|
||||||
|
### View All Roster Secrets
|
||||||
|
|
||||||
|
1. Open Seahorse
|
||||||
|
2. Navigate to "Login" keyring
|
||||||
|
3. Search or filter for: `Roster`
|
||||||
|
4. All Roster secrets appear
|
||||||
|
|
||||||
|
### Backup Secrets
|
||||||
|
|
||||||
|
Seahorse can export keyring for backup:
|
||||||
|
1. File → Export
|
||||||
|
2. Select secrets to export
|
||||||
|
3. Choose secure location
|
||||||
|
|
||||||
|
### Delete All Roster Secrets
|
||||||
|
|
||||||
|
1. Search for "Roster" in Seahorse
|
||||||
|
2. Select all Roster entries
|
||||||
|
3. Right-click → Delete
|
||||||
|
|
||||||
|
## Migration from Plain Variables
|
||||||
|
|
||||||
|
If you have existing projects with secrets in plain text:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Step 1: Identify secrets in your variables
|
||||||
|
// Look for: api_key, password, token, secret, private_key
|
||||||
|
|
||||||
|
// Step 2: For each secret variable:
|
||||||
|
// - Open Environments dialog
|
||||||
|
// - Click lock icon
|
||||||
|
// - Values automatically move to keyring
|
||||||
|
|
||||||
|
// Step 3: Verify in Seahorse
|
||||||
|
// - Open "Passwords and Keys"
|
||||||
|
// - Check secrets appear under "Login" keyring
|
||||||
|
```
|
||||||
|
|
||||||
|
Your JSON file will now have empty strings, and secrets are encrypted.
|
||||||
|
|
||||||
|
## Platform Differences
|
||||||
|
|
||||||
|
### Native Installation
|
||||||
|
|
||||||
|
- Keyring: `~/.local/share/keyrings/`
|
||||||
|
- Direct access to system keyring
|
||||||
|
- No special permissions needed
|
||||||
|
|
||||||
|
### Flatpak Installation
|
||||||
|
|
||||||
|
- Keyring: Same system keyring (shared)
|
||||||
|
- Requires D-Bus permission: `--talk-name=org.freedesktop.secrets`
|
||||||
|
- Sandboxed but can access keyring with permission
|
||||||
|
|
||||||
|
Both installations share the same keyring - secrets work across install methods!
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [[Variables]] - Learn about regular variables
|
||||||
|
- [[Scripts]] - Use variables in automation scripts
|
||||||
|
- [[API-Reference]] - Complete JavaScript API documentation
|
||||||
356
Variables.md
Normal file
356
Variables.md
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
# Variables
|
||||||
|
|
||||||
|
Variables allow you to reuse values across multiple requests and switch between different environments (development, staging, production) with ease.
|
||||||
|
|
||||||
|
## What are Variables?
|
||||||
|
|
||||||
|
Variables are placeholder values that you can reference in your requests using the `{{variable_name}}` syntax. When you send a request, Roster automatically replaces these placeholders with the actual values from your selected environment.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```
|
||||||
|
URL: {{base_url}}/users
|
||||||
|
Headers:
|
||||||
|
Authorization: Bearer {{api_token}}
|
||||||
|
```
|
||||||
|
|
||||||
|
When sent with the "Production" environment:
|
||||||
|
```
|
||||||
|
URL: https://api.example.com/users
|
||||||
|
Headers:
|
||||||
|
Authorization: Bearer prod-token-abc123
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environments
|
||||||
|
|
||||||
|
Environments are collections of variable values. Common environment names:
|
||||||
|
- **Production** - Live API credentials
|
||||||
|
- **Staging** - Pre-production testing
|
||||||
|
- **Development** - Local development server
|
||||||
|
|
||||||
|
Each project can have multiple environments, and each environment has its own set of variable values.
|
||||||
|
|
||||||
|
## Creating Environments
|
||||||
|
|
||||||
|
### Step 1: Open Environments Dialog
|
||||||
|
|
||||||
|
1. Select a project from the sidebar
|
||||||
|
2. Click the **"Environments"** button in the header bar
|
||||||
|
|
||||||
|
### Step 2: Add Environment
|
||||||
|
|
||||||
|
1. Click **"Add Environment"** button
|
||||||
|
2. Enter name (e.g., "Production", "Development")
|
||||||
|
3. Click **"Add"**
|
||||||
|
|
||||||
|
The environment appears as a new column in the table.
|
||||||
|
|
||||||
|
### Step 3: Add Variables
|
||||||
|
|
||||||
|
1. Click the **"+"** button at the bottom of the variable list
|
||||||
|
2. Enter variable name (e.g., `base_url`)
|
||||||
|
3. Click **"Add"**
|
||||||
|
|
||||||
|
The variable appears as a new row in the table.
|
||||||
|
|
||||||
|
### Step 4: Set Values
|
||||||
|
|
||||||
|
Click in the cells to enter values for each environment:
|
||||||
|
|
||||||
|
| Variable | Production | Development |
|
||||||
|
|----------|-----------|-------------|
|
||||||
|
| base_url | `https://api.example.com` | `http://localhost:3000` |
|
||||||
|
| timeout | `30` | `60` |
|
||||||
|
|
||||||
|
Click **"Done"** to save.
|
||||||
|
|
||||||
|
## Using Variables in Requests
|
||||||
|
|
||||||
|
### Variable Syntax
|
||||||
|
|
||||||
|
Use double curly braces: `{{variable_name}}`
|
||||||
|
|
||||||
|
Variables work in:
|
||||||
|
- **URL**: `{{base_url}}/users`
|
||||||
|
- **Headers**: `Authorization: Bearer {{token}}`
|
||||||
|
- **Request Body**: `{"api_key": "{{api_key}}"}`
|
||||||
|
|
||||||
|
### Select Environment
|
||||||
|
|
||||||
|
1. Open a request tab
|
||||||
|
2. Use the **environment dropdown** (top of request panel)
|
||||||
|
3. Select environment (e.g., "Production")
|
||||||
|
4. All variables in the request will use values from this environment
|
||||||
|
|
||||||
|
### Visual Indicators
|
||||||
|
|
||||||
|
**Defined variables** - Normal appearance
|
||||||
|
|
||||||
|
**Undefined variables** - Highlighted with a warning color
|
||||||
|
- Variable name exists in `{{...}}` syntax
|
||||||
|
- But not defined in current environment
|
||||||
|
|
||||||
|
## Managing Variables
|
||||||
|
|
||||||
|
### Rename Variable
|
||||||
|
|
||||||
|
1. Open **Environments** dialog
|
||||||
|
2. Click on variable name
|
||||||
|
3. Edit the name
|
||||||
|
4. Press Enter
|
||||||
|
|
||||||
|
The variable is renamed across all environments automatically.
|
||||||
|
|
||||||
|
### Delete Variable
|
||||||
|
|
||||||
|
1. Open **Environments** dialog
|
||||||
|
2. Click the **trash icon** next to variable name
|
||||||
|
3. Confirm deletion
|
||||||
|
|
||||||
|
The variable is removed from all environments.
|
||||||
|
|
||||||
|
### Rename Environment
|
||||||
|
|
||||||
|
1. Open **Environments** dialog
|
||||||
|
2. Click the **edit icon** on environment column header
|
||||||
|
3. Enter new name
|
||||||
|
4. Click **"Save"**
|
||||||
|
|
||||||
|
### Delete Environment
|
||||||
|
|
||||||
|
1. Open **Environments** dialog
|
||||||
|
2. Click the **trash icon** on environment column header
|
||||||
|
3. Confirm deletion
|
||||||
|
|
||||||
|
All variable values for that environment are deleted.
|
||||||
|
|
||||||
|
**Note:** Each project must have at least one environment.
|
||||||
|
|
||||||
|
## Common Variable Patterns
|
||||||
|
|
||||||
|
### Base URL
|
||||||
|
|
||||||
|
```
|
||||||
|
Variable: base_url
|
||||||
|
Production: https://api.example.com
|
||||||
|
Development: http://localhost:3000
|
||||||
|
|
||||||
|
Usage: {{base_url}}/users/123
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Version
|
||||||
|
|
||||||
|
```
|
||||||
|
Variable: api_version
|
||||||
|
Production: v2
|
||||||
|
Development: v2-beta
|
||||||
|
|
||||||
|
Usage: {{base_url}}/{{api_version}}/users
|
||||||
|
```
|
||||||
|
|
||||||
|
### Timeout Values
|
||||||
|
|
||||||
|
```
|
||||||
|
Variable: timeout
|
||||||
|
Production: 30
|
||||||
|
Development: 60
|
||||||
|
|
||||||
|
Usage: X-Timeout: {{timeout}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Identifier
|
||||||
|
|
||||||
|
```
|
||||||
|
Variable: env
|
||||||
|
Production: prod
|
||||||
|
Development: dev
|
||||||
|
|
||||||
|
Usage: X-Environment: {{env}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### User ID for Testing
|
||||||
|
|
||||||
|
```
|
||||||
|
Variable: test_user_id
|
||||||
|
Production: 12345
|
||||||
|
Development: 1
|
||||||
|
|
||||||
|
Usage: {{base_url}}/users/{{test_user_id}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Script Integration
|
||||||
|
|
||||||
|
Variables can be accessed and modified from [[Scripts]]:
|
||||||
|
|
||||||
|
### Reading Variables (Preprocessing)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const baseUrl = roster.getVariable('base_url');
|
||||||
|
const apiKey = roster.getVariable('api_key');
|
||||||
|
|
||||||
|
console.log('Using base URL:', baseUrl);
|
||||||
|
request.headers['X-API-Key'] = apiKey;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Writing Variables (Postprocessing)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Extract token from response and save for next request
|
||||||
|
const data = JSON.parse(response.body);
|
||||||
|
roster.setVariable('auth_token', data.access_token);
|
||||||
|
roster.setVariable('user_id', data.user_id);
|
||||||
|
console.log('Saved token for user:', data.user_id);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Batch Updates
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Update multiple variables at once
|
||||||
|
roster.setVariables({
|
||||||
|
access_token: data.access_token,
|
||||||
|
refresh_token: data.refresh_token,
|
||||||
|
user_id: data.user.id,
|
||||||
|
user_name: data.user.name
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Scripts automatically update variables in the currently selected environment.
|
||||||
|
|
||||||
|
## Variable Scoping
|
||||||
|
|
||||||
|
**Project Level:**
|
||||||
|
- Variables are defined at the project level
|
||||||
|
- All requests in the project can access these variables
|
||||||
|
|
||||||
|
**Environment Level:**
|
||||||
|
- Variable values are specific to each environment
|
||||||
|
- Switching environments switches all values at once
|
||||||
|
|
||||||
|
**Not Global:**
|
||||||
|
- Variables from one project cannot be used in another project
|
||||||
|
- Each project has its own isolated set of variables
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Use Descriptive Names
|
||||||
|
|
||||||
|
Good:
|
||||||
|
- `base_url`
|
||||||
|
- `api_key`
|
||||||
|
- `github_token`
|
||||||
|
- `stripe_secret_key`
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
- `url1`
|
||||||
|
- `key`
|
||||||
|
- `token`
|
||||||
|
|
||||||
|
### Group Related Variables
|
||||||
|
|
||||||
|
```
|
||||||
|
# API Configuration
|
||||||
|
base_url
|
||||||
|
api_version
|
||||||
|
timeout
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
api_key
|
||||||
|
api_secret
|
||||||
|
auth_token
|
||||||
|
|
||||||
|
# Test Data
|
||||||
|
test_user_id
|
||||||
|
test_email
|
||||||
|
```
|
||||||
|
|
||||||
|
### Keep Environments Consistent
|
||||||
|
|
||||||
|
All environments should have the same variable names with different values:
|
||||||
|
|
||||||
|
| Variable | Production | Development |
|
||||||
|
|----------|-----------|-------------|
|
||||||
|
| base_url | `api.example.com` | `localhost:3000` |
|
||||||
|
| api_key | `prod-key-***` | `dev-key-***` |
|
||||||
|
| timeout | `30` | `60` |
|
||||||
|
|
||||||
|
### Use Sensitive Variables for Secrets
|
||||||
|
|
||||||
|
**DO NOT** store secrets in regular variables - they are saved in plain text!
|
||||||
|
|
||||||
|
Use [[Sensitive-Variables]] instead:
|
||||||
|
- API keys
|
||||||
|
- Passwords
|
||||||
|
- Tokens
|
||||||
|
- Secret keys
|
||||||
|
|
||||||
|
## Undefined Variables
|
||||||
|
|
||||||
|
When Roster encounters `{{variable_name}}` but the variable is not defined:
|
||||||
|
|
||||||
|
**Visual Warning:**
|
||||||
|
- The entry field with undefined variable is highlighted
|
||||||
|
- Warning color indicates missing variable
|
||||||
|
|
||||||
|
**Request Behavior:**
|
||||||
|
- The literal text `{{variable_name}}` is sent
|
||||||
|
- No error is thrown
|
||||||
|
- Check the console for warnings
|
||||||
|
|
||||||
|
**Fix:**
|
||||||
|
1. Open **Environments** dialog
|
||||||
|
2. Add the missing variable
|
||||||
|
3. Set its value in current environment
|
||||||
|
|
||||||
|
## Environment Switching
|
||||||
|
|
||||||
|
Switch environments to test the same request against different APIs:
|
||||||
|
|
||||||
|
**Example Workflow:**
|
||||||
|
1. Create request: `GET {{base_url}}/users`
|
||||||
|
2. Select "Development" environment
|
||||||
|
3. Send request (goes to `http://localhost:3000/users`)
|
||||||
|
4. Select "Production" environment
|
||||||
|
5. Send request (goes to `https://api.example.com/users`)
|
||||||
|
|
||||||
|
Same request, different targets!
|
||||||
|
|
||||||
|
## Advanced Topics
|
||||||
|
|
||||||
|
### Variables in Request Body
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"api_key": "{{api_key}}",
|
||||||
|
"environment": "{{env}}",
|
||||||
|
"user_id": {{user_id}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Numeric values should not have quotes if you want them as numbers.
|
||||||
|
|
||||||
|
### Nested Variable References
|
||||||
|
|
||||||
|
Variables can contain other variables:
|
||||||
|
```
|
||||||
|
Variable: full_url
|
||||||
|
Value: {{base_url}}/{{api_version}}/users
|
||||||
|
```
|
||||||
|
|
||||||
|
Both `{{base_url}}` and `{{api_version}}` will be substituted.
|
||||||
|
|
||||||
|
### Dynamic Variables from Scripts
|
||||||
|
|
||||||
|
Variables don't have to be manually created - scripts can create them:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Preprocessing script
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
roster.setVariable('request_timestamp', timestamp);
|
||||||
|
|
||||||
|
// Now you can use {{request_timestamp}} in the request
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [[Sensitive-Variables]] - Store API keys and secrets securely
|
||||||
|
- [[Scripts]] - Automate variable management with JavaScript
|
||||||
|
- [[API-Reference]] - Complete API for working with variables
|
||||||
Loading…
x
Reference in New Issue
Block a user