Global functions
Describes Optimizely Connect Platform (OCP) global functions, including execution, versioning, definition, and examples.
Note
A function in OCP is a webhook.
In Optimizely Connect Platform (OCP), global functions are very similar to regular functions with the notable exceptions being they do not execute in an installation context (single Optimizely Data Platform (ODP) account) and they are versioned differently.
Global function execution
Global functions are typically required as webhook receivers when providers do not support the registration of webhooks at the installation (ODP account) level. Instead, a single webhook is used for all accounts with installation information provided as part of the HTTP request using a query string parameter, HTTP header, POST body field, and so on. The main purpose of a global function is to provide routing to regular function endpoints defined in your application.
Global function versioning
Note
OCP follows Semantic Versioning (semver) specification for version management. For more information on OCP app versioning, see Version an app.
When executing global functions, OCP ignores pre-release versions and uses the highest currently deployed full-release version of an app. For example, if you have deployed versions 1.0.0
, 1.1.0
, and 1.2.0
of your app, OCP only uses the global functions defined in version 1.2.0
, regardless of the version each user has installed.
However, if you have only deployed pre-release versions of an app (for example, 1.0.0-dev.1
, 1.0.0-beta.2
, or 1.0.0-private
), OCP uses the highest currently deployed pre-release version of an app. For example, if you have deployed pre-release versions 1.0.0-dev.1
, 1.0.0-dev.2
, and 1.1.0-dev.1
of your app, OCP only uses the global functions defined in version 1.1.0-dev.1
.
Note
Make sure that new versions of your application are always backward compatible.
Define global functions
Like regular functions, you must define global functions in your application's app.yml
file with one addition; mark them as global using the global
property. For example:
functions:
handle_event_global:
entry_point: HandleEventGlobal
description: Relays handle_event calls the appropriate install function
global: true
Below are the requirements for any global functions you define in your app.yaml
file:
- Add the global function's code in the
src/functions
directory. - The file and class name must follow the same rules as for regular functions (match the
entry_point
defined in theapp.yaml
file).
Important
If you modify a global function to a function with installation resolution between app versions, without changing the name of the function, both the global function and function with installation resolution will be deployed under the same public URL. In case an incoming request matches the defined installation resolution type, key, and value from the app manifest, OCP only calls the function with installation resolution. If the request does not match the defined installation resolution attributes, OCP calls the global function.
Webhook URLs for global functions
Global functions that you define in the app.yaml
file are provided a public URL in the following format: https://[OCP-REGIONAL-DOMAIN]/[APP_ID]/[GLOBAL_FN_NAME]
You can get the exact URL of an app's global functions using the ocp directory list-global-functions
command. For example:
$ ocp directory list-global-functions ocp_shakedown
https://function.zaius.app/ocp_shakedown/global_fn
Global functions have access to the HTTP request just like a regular function. Access to built-in storage is limited to only the shared Key Value Store storage instance. In addition, account context information is missing and all API calls using the ODP Node SDK are not permitted.
Global function example
import * as App from '@zaiusinc/app-sdk';
import {logger, storage} from '@zaiusinc/app-sdk';
import fetch from 'node-fetch';
/**
* Relays an event to a function. The setup here is during the Lifecycle#onInstall
* hook a record of the external tracker id -> zaius installation id is persisted in
* the shared key-value store. This information is used by the global function to
* look up the correct endpoint URL of the function and relay the request to it.
*/
export class HandleEventGlobal extends App.GlobalFunction {
/**
* Relay an event to an install fn
* @returns App.Response as the HTTP response
*/
public async perform(): Promise<App.Response> {
// ODP account information is provided in the query string of the hook request
const trackerId = this.request.params['tracker_id'] as string;
logger.info(`HandleEventGlobal call for tracker ${trackerId}`);
if (!trackerId) {
return new App.Response(400, 'Missing required tracker_id parameter');
}
// find the installation id
const installation = await storage.sharedKvStore.get(trackerId);
if (!installation) {
return new App.Response(404, `Install not found for tracker ${trackerId}`);
}
return this.relay(installation.installId as number);
}
private async relay(installId: number): Promise<App.Response> {
// get all the hook endpoints for the installation
const fns = await App.functions.getEndpoints(installId);
const email = this.request.params['email'] as string;
logger.info(
`Relaying hook for install ${installId} to: ${fns.handle_event}?email=${email}`
);
// relay the request to the handle_event fn endpoint
const result = await fetch(`${fns.handle_event}?email=${email}`, {
method: 'POST',
body: this.request.body
});
// return resulting info in the response
return new App.Response(result.status, result.body);
}
}
Updated 8 months ago