Skip to main content

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.

ButtonDescription
NewClears the form to create a new web service.
CloneDuplicates the current service for editing under a new name.
ExportDownloads the service configuration as a JSON file.
ImportLoads a service from a previously exported JSON file.
DeleteDeletes 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:

TemplateDescription
JSON APIREST endpoint returning JSON, with GET/POST routing.
Webhook ReceiverAccepts incoming webhooks and processes them.
HTML PageServes a custom HTML page with dynamic data.
ProxyForwards requests to an external API.
Form HandlerServes an HTML form and processes submissions.
CSV ExportExports 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

FieldDescription
NameRequired. Internal identifier (auto-formatted to lowercase_with_underscores). Becomes the URL path: /web_service/{name}.
MethodHTTP method: ANY (all methods), GET, POST, PUT, DELETE, PATCH, or HEAD. Use ANY to handle multiple methods in a single handler.
Content TypeResponse content type with common suggestions: application/json, text/html, text/plain, text/csv, etc.
DescriptionOptional description of what this service does.

Authentication

FieldDescription
Auth TypeNone, Basic Auth, API Key, or Bearer Token.
EnabledToggle to enable or disable the service.

Basic Auth fields:

  • Username and Password — checked against the Authorization: Basic header.

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: Bearer header.

Request Handler Script

A full-featured script editor for writing the JavaScript handler. The script must define a handleRequest function.

Request Object (req)

PropertyDescription
req.methodHTTP method string (GET, POST, etc.).
req.params.pathSub-path after the service name (e.g., /users/42).
req.params.segmentsPath segments as an array (e.g., ['users', '42']).
req.bodyParsed request body (JSON object if parseable, otherwise raw string).
req.queryURL query parameters as key/value pairs.
req.headersHTTP request headers (lowercased keys).

Response Object (res)

MethodDescription
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

VariableDescription
gemGemServer instance — full access to queryAsync, commandAsync, setAttributeAsync, etc.
storePer-service in-memory key-value store (persists across requests, resets on service reload).
fetchGlobal fetch for making outbound HTTP requests.
Buffer, URL, URLSearchParamsStandard Node.js utilities.
setTimeout, clearTimeoutTimer functions.
JSON, Math, Date, etc.Standard JavaScript globals.

Action Buttons

ButtonDescription
ReloadReloads the service handler to apply the latest saved script.
Create / Update ServiceSaves 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

FieldDescription
Path SuffixOptional sub-path appended to the service URL (e.g., /devices/42).
Method OverrideOverride the service's configured method for this test request.
HeadersAdd custom request headers as key-value pairs.
Query ParametersAdd URL query parameters as key-value pairs.
Request BodyRequest 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
  • Macros — Triggering macros from webhooks
  • Attributes — Updating attributes from webhooks
  • Triggers — Webhook-triggered automation
  • MQTT — Alternative integration via MQTT