JSON Reference
The JSON
object is available within Loadster Code Blocks and provides methods for parsing and creating JSON data. These methods make it easy to work with API responses, create request payloads, and extract data from JSON structures programmatically.
Understanding JSON Processing in Loadster
In Loadster, JSON (JavaScript Object Notation) is the most common data format for REST APIs, web services, and modern applications. JSON is a lightweight, text-based format that represents structured data using objects, arrays, strings, numbers, booleans, and null values.
JSON structure examples:
{
"user": {
"id": 123,
"name": "John Doe",
"active": true,
"roles": ["user", "admin"],
"profile": {
"email": "john@example.com",
"lastLogin": null
}
}
}
In this example:
- Objects are enclosed in
{}
with key-value pairs - Arrays are enclosed in
[]
with comma-separated values - Strings are enclosed in double quotes
- Numbers, booleans (true/false), and null are used as-is
Loadster uses the standard JavaScript JSON.parse()
and JSON.stringify()
methods, which work synchronously across both Protocol Scripts and Browser Scripts. You’ll most commonly need to manually work with JSON when using Protocol Scripts to test REST APIs and web services, though JSON processing is available in any type of Loadster script. All JSON operations are synchronous - no need for await
or promise chains - and bot variables store only strings, so convert numbers and booleans to strings when storing extracted data.
JSON Parsing
These methods convert JSON strings into JavaScript objects that you can navigate and manipulate.
JSON.parse(jsonString)
Parse a JSON string and return a JavaScript object.
// Parse simple JSON
const simple = JSON.parse('{"name": "John", "age": 30}');
console.log(simple.name); // "John"
// Parse API response
const response = http.get('https://api.example.com/user');
const user = JSON.parse(response.string());
// Parse complex nested JSON
const complexJson = '{"users": [{"id": 1, "profile": {"email": "john@example.com"}}]}';
const data = JSON.parse(complexJson);
console.log(data.users[0].profile.email); // "john@example.com"
Parameters:
jsonString
- The JSON string to parse
This method parses a JSON string and returns a JavaScript object. The resulting object allows you to access properties using dot notation or bracket notation.
Note: JSON parsing uses standard JavaScript methods and is synchronous - no need for await
or promise chains. Always wrap JSON parsing in try-catch blocks to handle malformed JSON gracefully.
JSON Creation
These methods convert JavaScript objects into JSON strings for sending in HTTP requests.
JSON.stringify(object)
Convert a JavaScript object to a JSON string.
// Simple object to JSON
const user = {
name: 'John Doe',
email: 'john@example.com',
age: 30,
active: true
};
const userJson = JSON.stringify(user);
console.log(userJson); // '{"name":"John Doe","email":"john@example.com","age":30,"active":true}'
// Complex nested object
const orderData = {
orderId: formats.uuid(),
customer: {
id: bot.getVariable('customerId'),
name: bot.getVariable('customerName'),
tier: 'premium'
},
items: [
{ productId: 'prod-123', quantity: 2, price: 29.99 },
{ productId: 'prod-456', quantity: 1, price: 19.99 }
],
timestamp: new Date().toISOString()
};
// Send as JSON request
const response = http.post('https://api.example.com/orders', JSON.stringify(orderData), {
headers: { 'Content-Type': 'application/json' }
});
Parameters:
object
- The JavaScript object to convert to JSON
This method converts JavaScript objects, arrays, strings, numbers, booleans, and null values into a JSON string representation that can be sent in HTTP requests.
Note: Remember to set Content-Type: application/json
headers when sending JSON data in HTTP requests.
Building Dynamic JSON Payloads
// Build JSON dynamically based on bot variables and test data
const requestData = {
user: {
id: bot.getVariable('userId'),
name: bot.getVariable('userName'),
email: bot.getVariable('userEmail')
},
preferences: {
theme: 'dark',
notifications: true,
language: 'en'
},
metadata: {
sessionId: formats.uuid(),
timestamp: formats.timestamp('%Y-%M-%d %H:%m:%s'),
userAgent: 'LoadsterBot/1.0',
testRun: bot.getVariable('testRunId') || 'unknown'
}
};
// Add conditional fields
const userRole = bot.getVariable('userRole');
if (userRole) {
requestData.user.role = userRole;
}
// Add array data
const favoriteProducts = bot.getVariable('favoriteProducts');
if (favoriteProducts) {
requestData.favorites = favoriteProducts.split(',').map(id => ({ productId: id.trim() }));
}
const jsonPayload = JSON.stringify(requestData);
console.log('Sending JSON payload:', jsonPayload);
const response = http.put('https://api.example.com/profile', jsonPayload, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${bot.getVariable('authToken')}`
}
});
This example shows how to build complex JSON payloads dynamically using bot variables and conditional logic.
JSON Response Processing and Validation
These examples show how to extract and work with data from JSON API responses, including validation within HTTP request validators.
Basic JSON Parsing
// Parse JSON response from an API
const response = http.get('https://api.example.com/users');
const data = JSON.parse(response.string());
// Access different data types
console.log(`Found ${data.users.length} users`); // Number
console.log(`Status: ${data.status}`); // String
console.log(`Success: ${data.success}`); // Boolean
console.log(`Page: ${data.pagination.page}`); // Nested object
This example shows how to parse a basic JSON response and access different types of data within the structure.
Extracting Data for Variables
const response = http.get('https://api.example.com/user/123');
const user = JSON.parse(response.string());
// Extract specific fields with null checks
const userId = user.id || 'unknown';
const userName = user.name || 'Anonymous';
const userEmail = user.profile ? user.profile.email : null;
const isActive = user.active === true;
const lastLogin = user.lastLogin || null;
// Store in bot variables for later use
bot.setVariable('userId', userId.toString());
bot.setVariable('userName', userName);
bot.setVariable('userEmail', userEmail || '');
bot.setVariable('userActive', isActive.toString());
console.log(`Extracted user: ${userName} (ID: ${userId}, Active: ${isActive})`);
This example shows how to safely extract data from JSON with proper null checking and type conversion for bot variables.
Note: Use proper null checking when accessing nested properties to avoid runtime errors. Bot variables store only strings - convert numbers and booleans to strings when storing.
Working with JSON Arrays
const response = http.get('https://api.example.com/products');
const data = JSON.parse(response.string());
// Check if array exists and has items
if (data.products && Array.isArray(data.products)) {
console.log(`Processing ${data.products.length} products`);
// Iterate through array
for (let i = 0; i < data.products.length; i++) {
const product = data.products[i];
const name = product.name || 'Unnamed Product';
const price = product.price || 0;
const category = product.category || 'Uncategorized';
const inStock = product.inventory ? product.inventory.inStock : false;
console.log(`Product ${i + 1}: ${name} - $${price} (${category}) - Stock: ${inStock}`);
// Store first product details
if (i === 0) {
bot.setVariable('firstProductId', product.id.toString());
bot.setVariable('firstProductName', name);
}
}
} else {
console.warn('No products array found in response');
}
This example demonstrates safe array processing with proper checks and data extraction.
Nested JSON Objects
const response = http.get('https://api.example.com/order/456');
const order = JSON.parse(response.string());
// Safely access nested properties
const orderId = order.id;
const customerName = order.customer ? order.customer.name : 'Unknown Customer';
const customerEmail = order.customer && order.customer.contact ? order.customer.contact.email : null;
// Access deeply nested shipping address
const shippingAddress = order.shipping && order.shipping.address ?
`${order.shipping.address.street}, ${order.shipping.address.city}` :
'No shipping address';
// Process items array
const itemCount = order.items ? order.items.length : 0;
let total = 0;
if (order.items && Array.isArray(order.items)) {
for (let i = 0; i < order.items.length; i++) {
const item = order.items[i];
const itemPrice = item.price || 0;
const itemQuantity = item.quantity || 1;
total += itemPrice * itemQuantity;
console.log(`Item ${i + 1}: ${item.name} - $${itemPrice} x ${itemQuantity}`);
}
}
// Store calculated values
bot.setVariable('orderId', orderId.toString());
bot.setVariable('orderCustomer', customerName);
bot.setVariable('orderTotal', total.toString());
bot.setVariable('orderItemCount', itemCount.toString());
console.log(`Order ${orderId}: ${customerName} - ${itemCount} items, Total: $${total}`);
This example shows safe navigation through nested JSON objects with proper null checking and error handling.
Validating JSON Response Structure in HTTP Requests
const response = http.get('https://api.example.com/status', {
validators: [
(response) => {
try {
const data = JSON.parse(response.string());
// Check required fields exist
if (typeof data.status !== 'string') {
console.error('Missing or invalid status field');
return false;
}
// Validate status value
const validStatuses = ['ok', 'error', 'maintenance'];
if (!validStatuses.includes(data.status)) {
console.error(`Invalid status: ${data.status}`);
return false;
}
// Check timestamp is present and valid
if (!data.timestamp || typeof data.timestamp !== 'string') {
console.error('Missing or invalid timestamp');
return false;
}
return data.status === 'ok';
} catch (e) {
console.error('Failed to parse JSON response:', e.message);
return false;
}
}
]
});
This validator thoroughly checks the JSON structure and validates that required fields exist with the correct data types.
Note: Use validators to safely extract and validate data from JSON responses, ensuring your tests handle unexpected response formats gracefully.
Extracting Data with Validators
const loginData = {
username: bot.getVariable('testUsername') || 'testuser',
password: bot.getVariable('testPassword') || 'testpass'
};
const response = http.post('https://api.example.com/login', JSON.stringify(loginData), {
headers: { 'Content-Type': 'application/json' },
validators: [
(response) => {
try {
const data = JSON.parse(response.string());
// Check for successful login
if (!data.success) {
console.error('Login failed:', data.message || 'Unknown error');
return false;
}
// Extract and validate token
if (data.token && typeof data.token === 'string' && data.token.length > 0) {
bot.setVariable('authToken', data.token);
// Extract additional user info if available
if (data.user) {
bot.setVariable('currentUserId', data.user.id ? data.user.id.toString() : '');
bot.setVariable('currentUserRole', data.user.role || 'user');
}
// Extract token expiration if available
if (data.expiresIn) {
bot.setVariable('tokenExpiresIn', data.expiresIn.toString());
}
console.log('Login successful, token extracted');
return true;
}
console.error('Login response missing valid token');
return false;
} catch (e) {
console.error('Failed to parse login response:', e.message);
return false;
}
}
]
});
This example shows comprehensive data extraction within a validator, including error handling and multiple value extraction.
Complex JSON Validation
const response = http.get('https://api.example.com/orders', {
validators: [
(response) => {
try {
const data = JSON.parse(response.string());
// Validate root structure
if (!data || typeof data !== 'object') {
console.error('Response is not a valid object');
return false;
}
// Validate required fields exist
if (!data.orders || !Array.isArray(data.orders)) {
console.error('Missing or invalid orders array');
return false;
}
// Validate pagination info if present
if (data.pagination) {
if (typeof data.pagination.page !== 'number' ||
typeof data.pagination.total !== 'number') {
console.error('Invalid pagination data');
return false;
}
}
// Validate each order has required fields
for (let i = 0; i < data.orders.length; i++) {
const order = data.orders[i];
// Check required order fields
if (!order.id || typeof order.id !== 'string') {
console.error(`Order ${i} missing valid id`);
return false;
}
if (!order.customer || typeof order.customer.name !== 'string') {
console.error(`Order ${order.id} missing valid customer`);
return false;
}
if (!order.items || !Array.isArray(order.items) || order.items.length === 0) {
console.error(`Order ${order.id} missing valid items`);
return false;
}
// Validate each item
for (let j = 0; j < order.items.length; j++) {
const item = order.items[j];
if (!item.productId || typeof item.quantity !== 'number' || typeof item.price !== 'number') {
console.error(`Order ${order.id} item ${j} has invalid data`);
return false;
}
}
}
console.log(`Validated ${data.orders.length} orders successfully`);
return true;
} catch (e) {
console.error('JSON validation error:', e.message);
return false;
}
}
]
});
This comprehensive validator checks the entire JSON structure, validates data types, and provides detailed error messages for debugging.
JSON Examples
These examples demonstrate typical JSON processing scenarios in load testing.
Safe JSON Parsing with Error Handling
When testing APIs that might return malformed JSON or unexpected response formats, it’s crucial to handle parsing errors gracefully. This example creates a reusable utility function that safely parses JSON and returns structured error information when parsing fails. This approach prevents your load test from crashing due to malformed responses.
function safeJsonParse(jsonString) {
try {
return {
success: true,
data: JSON.parse(jsonString)
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
const response = http.get('https://api.example.com/data');
const result = safeJsonParse(response.string());
if (result.success) {
console.log('JSON parsed successfully');
const data = result.data;
// Process data safely
if (data.users && Array.isArray(data.users)) {
console.log(`Found ${data.users.length} users`);
// Process users...
}
} else {
console.error('Failed to parse JSON:', result.error);
console.log('Response was:', response.string().substring(0, 200) + '...');
}
This error handling pattern ensures your load tests continue running even when encountering malformed responses, while providing detailed error information for debugging. The structured return value makes it easy to distinguish between parsing errors and successful parsing with empty or unexpected data.
JSON Data Validation Utility
Complex JSON responses often have deeply nested structures where certain fields are required for your test to proceed correctly. This example shows how to create a reusable validation utility that checks for the presence of required fields using dot notation paths. This is particularly useful when testing APIs that might return partial data or have optional fields.
function validateJsonStructure(data, requiredFields) {
for (let i = 0; i < requiredFields.length; i++) {
const field = requiredFields[i];
const keys = field.split('.');
let current = data;
for (let j = 0; j < keys.length; j++) {
const key = keys[j];
if (!current || typeof current !== 'object' || !(key in current)) {
console.error(`Missing required field: ${field}`);
return false;
}
current = current[key];
}
}
return true;
}
// Use the validator
const response = http.get('https://api.example.com/user/profile');
const parseResult = safeJsonParse(response.string());
if (parseResult.success) {
const data = parseResult.data;
const requiredFields = ['user.id', 'user.name', 'user.email', 'user.profile.createdAt'];
if (validateJsonStructure(data, requiredFields)) {
console.log('JSON structure validation passed');
// Extract validated data
bot.setVariable('userId', data.user.id.toString());
bot.setVariable('userName', data.user.name);
bot.setVariable('userEmail', data.user.email);
} else {
console.error('JSON structure validation failed');
}
}
This validation utility provides a clean way to verify that complex JSON responses contain all the fields your test expects. By validating the structure before attempting to extract data, you avoid runtime errors and can provide clear error messages when the API response format changes unexpectedly.
Chained API Calls with JSON
Realistic load testing often involves chaining multiple API calls where data from one response is used to make subsequent requests. This example demonstrates a typical user journey where you first get user information, then fetch their orders, and finally get details about their most recent order. This pattern simulates how real applications navigate through related data.
// Chain multiple API calls using JSON data extraction
const userResponse = http.get(`https://api.example.com/users/${bot.getVariable('testUserId')}`);
const userResult = safeJsonParse(userResponse.string());
if (userResult.success) {
const userData = userResult.data;
console.log(`Processing user: ${userData.name}`);
// Get user's orders using extracted ID
const ordersResponse = http.get(`https://api.example.com/users/${userData.id}/orders`);
const ordersResult = safeJsonParse(ordersResponse.string());
if (ordersResult.success && ordersResult.data.orders) {
const orders = ordersResult.data.orders;
console.log(`User has ${orders.length} orders`);
if (orders.length > 0) {
// Get details of the most recent order
const latestOrder = orders[0];
const orderResponse = http.get(`https://api.example.com/orders/${latestOrder.id}`);
const orderResult = safeJsonParse(orderResponse.string());
if (orderResult.success) {
const orderData = orderResult.data;
// Store order information for further testing
bot.setVariable('latestOrderId', orderData.id.toString());
bot.setVariable('latestOrderStatus', orderData.status);
bot.setVariable('latestOrderTotal', orderData.total.toString());
console.log(`Latest order ${orderData.id}: ${orderData.status} - $${orderData.total}`);
}
}
}
}
This chained approach creates realistic load patterns that test not just individual endpoints but also the relationships between them. Each step uses data from the previous response, creating a more authentic simulation of user behavior. The extracted order information can be used in subsequent test steps to simulate order management workflows.
Bulk Data Processing with JSON
Many modern APIs support bulk operations to improve efficiency when processing large datasets. This example demonstrates how to create and process bulk update requests with JSON payloads, including generating test data and handling bulk response processing. This pattern is essential for testing high-throughput scenarios and batch processing endpoints.
// Process bulk data operations with JSON arrays
const batchSize = parseInt(bot.getVariable('batchSize')) || 5;
const userIds = [];
// Generate test user IDs
for (let i = 0; i < batchSize; i++) {
userIds.push(formats.randomnumeric(6));
}
// Create bulk update payload
const bulkUpdateData = {
operation: 'bulk_update',
requestId: formats.uuid(),
updates: userIds.map(userId => ({
userId: userId,
status: 'active',
lastLogin: formats.timestamp('%Y-%M-%d %H:%m:%s'),
preferences: {
emailNotifications: true,
theme: Math.random() > 0.5 ? 'dark' : 'light'
}
})),
metadata: {
batchId: bot.getVariable('batchId') || formats.uuid(),
timestamp: new Date().toISOString(),
source: 'loadtest'
}
};
console.log(`Sending bulk update for ${bulkUpdateData.updates.length} users`);
const response = http.post('https://api.example.com/users/bulk-update',
JSON.stringify(bulkUpdateData), {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${bot.getVariable('authToken')}`
}
});
// Process bulk response
const result = safeJsonParse(response.string());
if (result.success && result.data.results) {
const successCount = result.data.results.filter(r => r.success).length;
const failureCount = result.data.results.length - successCount;
console.log(`Bulk update completed: ${successCount} success, ${failureCount} failures`);
bot.setVariable('bulkUpdateSuccess', successCount.toString());
bot.setVariable('bulkUpdateFailures', failureCount.toString());
}
Bulk operations are crucial for testing APIs at scale and ensuring they can handle high-volume requests efficiently. This pattern shows how to generate varied test data, construct complex payloads, and process bulk responses to validate both success and failure scenarios. The extracted metrics can be used to validate API performance and error handling under load.