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