Web Services
The Web Services page lets you create custom HTTP endpoints that external systems can call to interact with GEM. Each web service is a JavaScript handler function that processes incoming HTTP requests and returns a response. Services are accessible at /web_service/{name} and support sub-paths (e.g., /web_service/{name}/users/42).
Service Selection
At the top of the page is a Web Service dropdown listing all existing services.
| Button | Description |
|---|---|
| New | Clears the form to create a new web service. |
| Clone | Duplicates the current service for editing under a new name. |
| Export | Downloads the service configuration as a JSON file. |
| Import | Loads a service from a previously exported JSON file. |
| Delete | Deletes the currently selected service (with confirmation). |
Tabs
The page has three tabs: Configure, Test, and Request Log.
Configure Tab
Templates
When creating a new service, a row of template chips appears to pre-fill the script and settings:
| Template | Description |
|---|---|
| JSON API | REST endpoint returning JSON, with GET/POST routing. |
| Webhook Receiver | Accepts incoming webhooks and processes them. |
| HTML Page | Serves a custom HTML page with dynamic data. |
| Proxy | Forwards requests to an external API. |
| Form Handler | Serves an HTML form and processes submissions. |
| CSV Export | Exports GEM data as a downloadable CSV file. |
Click a template to load it. The template pre-fills the method, content type, description, and script.
Configuration
| Field | Description |
|---|---|
| Name | Required. Internal identifier (auto-formatted to lowercase_with_underscores). Becomes the URL path: /web_service/{name}. |
| Method | HTTP method: ANY (all methods), GET, POST, PUT, DELETE, PATCH, or HEAD. Use ANY to handle multiple methods in a single handler. |
| Content Type | Response content type with common suggestions: application/json, text/html, text/plain, text/csv, etc. |
| Description | Optional description of what this service does. |
Authentication
| Field | Description |
|---|---|
| Auth Type | None, Basic Auth, API Key, or Bearer Token. |
| Enabled | Toggle to enable or disable the service. |
Basic Auth fields:
- Username and Password — checked against the
Authorization: Basicheader.
API Key fields:
- Header Name — the header to check (default:
X-API-Key). - API Key — the expected key value.
Bearer Token fields:
- Bearer Token — checked against the
Authorization: Bearerheader.
Request Handler Script
A full-featured script editor for writing the JavaScript handler. The script must define a handleRequest function.
Request Object (req)
| Property | Description |
|---|---|
req.method | HTTP method string (GET, POST, etc.). |
req.params.path | Sub-path after the service name (e.g., /users/42). |
req.params.segments | Path segments as an array (e.g., ['users', '42']). |
req.body | Parsed request body (JSON object if parseable, otherwise raw string). |
req.query | URL query parameters as key/value pairs. |
req.headers | HTTP request headers (lowercased keys). |
Response Object (res)
| Method | Description |
|---|---|
res.json(data) | Send a JSON response. |
res.send(text) | Send a text/HTML response. |
res.status(code) | Set the HTTP status code (chainable). |
res.setHeader(name, value) | Set a response header. |
Available Globals
| Variable | Description |
|---|---|
gem | GemServer instance — full access to queryAsync, commandAsync, setAttributeAsync, etc. |
store | Per-service in-memory key-value store (persists across requests, resets on service reload). |
fetch | Global fetch for making outbound HTTP requests. |
Buffer, URL, URLSearchParams | Standard Node.js utilities. |
setTimeout, clearTimeout | Timer functions. |
JSON, Math, Date, etc. | Standard JavaScript globals. |
Action Buttons
| Button | Description |
|---|---|
| Reload | Reloads the service handler to apply the latest saved script. |
| Create / Update Service | Saves the service configuration. |
Test Tab
The Test tab lets you send requests to the service directly from the admin UI without external tools.
Request Configuration
| Field | Description |
|---|---|
| Path Suffix | Optional sub-path appended to the service URL (e.g., /devices/42). |
| Method Override | Override the service's configured method for this test request. |
| Headers | Add custom request headers as key-value pairs. |
| Query Parameters | Add URL query parameters as key-value pairs. |
| Request Body | Request body for POST/PUT/PATCH/DELETE requests (shown only for those methods). |
A URL preview shows the complete request URL with method badge.
Click Send Request to execute the test. The service is automatically reloaded before each test to ensure the latest script is used.
Response Display
The response section shows:
- Status code and status text (color-coded green for 2xx, red for 4xx/5xx)
- Elapsed time in milliseconds
- Content type
- Response headers in a collapsible table
- Response body with syntax highlighting
Request Log Tab
The Request Log tab shows a real-time stream of incoming requests to the selected service.
- Click Start to begin capturing requests.
- Click Stop to pause capture.
- Click Clear to empty the log.
Each entry shows:
- Time — Timestamp with millisecond precision.
- Method — HTTP method (GET, POST, etc.).
- Path — The sub-path of the request.
- Status — Response status code (color-coded).
- Elapsed — Response time in milliseconds.
The log retains up to 500 entries. Requests are also persisted to the Request History database for later review.
Example: JSON API with Sub-Path Routing
async function handleRequest(req, res) {
let [resource, id] = req.params.segments;
if (resource === 'zones') {
if (req.method === 'GET' && id) {
let zone = await gem.queryOne('zone', {id: parseInt(id)});
return res.json(zone || {error: 'not found'});
}
let zones = await gem.query('zone', {});
return res.json({zones});
}
res.status(404).json({error: 'not found'});
}
Usage:
GET /web_service/api/zones → list all zones
GET /web_service/api/zones/42 → get zone 42
Related Documentation
- Macros — Triggering macros from webhooks
- Attributes — Updating attributes from webhooks
- Triggers — Webhook-triggered automation
- MQTT — Alternative integration via MQTT