JavaScript Environment
Functions execute JavaScript in serverless containers. This page covers the execution environment, available objects, and best practices.
Available Objects
Core Objects
| Object | Description | Available In |
|---|---|---|
item | The current record being created, updated, or deleted | Trigger functions |
me | Current authenticated user | All functions (when authenticated) |
api | Information about the API | All functions |
secrets | Configured secrets (key/value pairs) | All functions |
req | Incoming HTTP request details | Trigger & Invocable functions |
res | Response object for custom responses | Invocable functions |
The item Object
For trigger functions, item contains the record being processed:
// Access item properties
console.log('Processing:', item.name);
console.log('Item ID:', item.id);
// Modify the item (for validation/transformation)
item.slug = item.title.toLowerCase().replace(/\s+/g, '-');
item.updatedAt = new Date().toISOString();
The me Object
Information about the current user:
| Property | Description |
|---|---|
id | User ID (GUID) |
email | User email |
name | User display name |
roles | Array of role IDs/names |
console.log('Request by:', me.name);
console.log('User email:', me.email);
The api Object
Information about the API:
| Property | Description |
|---|---|
id | API ID (GUID) |
name | API name |
tenantId | Tenant ID |
apiSettings | Array of settings [{key, value}] |
The req Object
Request details (trigger and invocable functions):
| Property | Description |
|---|---|
method | HTTP method (GET, POST, PUT, PATCH, DELETE) |
headers | Request headers (filtered for security) |
query | Query parameters |
body | Raw body string |
bodyJson | Parsed JSON body |
// Access request data
const method = req.method;
const contentType = req.headers['content-type'];
const page = req.query.page || 1;
const payload = req.bodyJson;
The res Object (Invocable Only)
Set custom responses in invocable functions:
| Property | Description |
|---|---|
status | HTTP status code (default: 200) |
headers | Response headers |
bodyJson | JSON response body |
body | Plain text response body |
// Return custom response
res = {
status: 201,
headers: { 'X-Custom-Header': 'value' },
bodyJson: { success: true, id: newItem.id }
};
Real-Time Channels
Functions can manage gated channels (channels with : in the name) using the built-in HTTP methods:
// Add client to a gated channel with send permission
await post('_rt/join', {
connectionId: req.connectionId,
channel: 'game:room-123',
readOnly: false // Client can send messages
});
// Add client as read-only listener
await post('_rt/join', {
connectionId: req.connectionId,
channel: 'announcements:system',
readOnly: true // Client can only receive
});
// Send message to any channel
await post('_rt/send', {
channel: 'announcements:system',
body: { type: 'notification', text: 'New update available' }
});
Gated channels (with :) can only be joined/messaged by functions. The readOnly parameter controls whether the client can send messages after joining.
See Real Time for channel types and client-side usage.
Built-in HTTP Methods
Functions have built-in async methods for API calls:
| Method | Description |
|---|---|
get(url) | GET request to API endpoint |
post(url, data) | POST request |
put(url, data) | PUT request |
patch(url, data) | PATCH request |
del(url) | DELETE request |
// Get all active products
const products = await get('products?filter=status eq "active"');
// Create a new order
const order = await post('orders', {
customerId: item.customerId,
total: item.total
});
// Update a record
await patch(`customers/${item.customerId}`, {
lastOrderDate: new Date().toISOString()
});
// Delete a record
await del(`temp-items/${item.id}`);
These methods automatically include authentication and use relative URLs within your API.
External HTTP Requests (fetch)
Use fetch for external API calls:
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Authorization': `Bearer ${secrets.EXTERNAL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: 'value' })
});
const data = await response.json();
The fetch function for external HTTP requests is only available on paid tiers. Free tier APIs cannot make external HTTP calls.
File Operations
| Method | Description |
|---|---|
getFileBase64(url) | Get file as Base64 string |
postFileBase64(url, fileName, content, mimeType) | Upload Base64 file |
// Download a file
const fileContent = await getFileBase64(`products/${item.id}/image`);
// Upload a file
await postFileBase64(
`products/${item.id}/thumbnail`,
'thumbnail.jpg',
resizedImageBase64,
'image/jpeg'
);
Secrets
Secrets are securely stored credentials injected into your function.
Configuring Secrets
- Create secrets in Settings → Secrets
- Select which secrets to inject when configuring your function
- Access them via the
secretsobject
Using Secrets
// Access secrets
const apiKey = secrets.STRIPE_API_KEY;
const webhookSecret = secrets.WEBHOOK_SECRET;
// Use in external calls
const response = await fetch('https://api.stripe.com/v1/charges', {
headers: {
'Authorization': `Bearer ${secrets.STRIPE_SECRET_KEY}`
}
});
Never log secrets or include them in error messages.
Logging
| Function | Severity |
|---|---|
console.log(message) or log(message) | Info |
logWarn(message) | Warning |
logError(message) | Error |
log('Processing started');
console.log('Item:', item.name);
logWarn('Customer has pending balance');
logError('Failed to sync with external service');
Logs include timestamps and milliseconds from execution start.
Context by Function Type
Trigger Functions
// Available: item, me, api, secrets, req
console.log('Processing item:', item.id);
console.log('Triggered by:', me.name);
console.log('Method:', req.method);
// Modify item before save
item.updatedBy = me.id;
Timer Functions
// Available: api, me (service account), secrets
// No item or request context
console.log('Running scheduled task for API:', api.name);
const items = await get('orders?filter=status eq "pending"');
// Process items...
Invocable Functions
// Available: req, res, me, api, secrets
const input = req.bodyJson;
const result = processData(input);
res = {
status: 200,
bodyJson: { success: true, result }
};
Error Handling
Throwing Errors
Throw errors to halt execution:
if (!item.email) {
throw new Error('Email is required');
}
Try-Catch
Handle errors gracefully:
try {
const external = await fetch(externalUrl);
if (!external.ok) {
throw new Error(`External API error: ${external.status}`);
}
} catch (error) {
logError('External call failed: ' + error.message);
// Handle gracefully or re-throw
}
Filtered Headers
For security, these headers are removed from req.headers:
authorization,cookie,hostx-forwarded-*,x-azure-*,x-arr-*- Other infrastructure headers
Best Practices
- Use
itemnotbody— For trigger functions, the record is initem - Use built-in methods —
get(),post(), etc. handle auth automatically - Validate inputs early — Check required fields at the start
- Handle errors gracefully — Use try-catch for external calls
- Log important operations — Aids debugging and auditing
- Keep secrets secure — Never expose in logs or responses
- Set appropriate timeouts — Prevent long-running functions