Functions Development Guidelines
Functions API
For more information about the Functions API, check out the Functions API documentation.
Introduction
- PubNub provides integrations with popular services through the Integration Catalog.
- Functions are implemented as a JavaScript module with a default export function. Go to guidelines to find out how to write code for each event type.
- PubNub provides libraries to assist in your Functions development.
- Asynchronous operations in Functions are handled through Promises. Refer to Promises.
- You can chain up to 5 functions to execute consecutively. Refer to Chaining Functions.
Development Guidelines
Code Structure
All Event Types except the On Request should have the following structure:
export default (request) => {
// Your business logic here
return request.ok();
// request.abort(); to fail execution
};
For all Event Types except On Request and On Interval, the request
object has two methods ok()
and abort()
. response
object isn't available. For detailed attributes refer to On Request and On Interval.
On Request
The On Request function should have the following structure:
export default (request, response) => {
// Your code here
return response.send();
};
For the On Request event type, the request
object has only one method json()
, a response
object only has send()
. For detailed attributes refer to On Request.
On Interval
The On Interval function should have the following structure:
export default (event) => {
// Your code here
return event.ok();
};
For the On Interval event type, the event
object has only one method ok()
. For detailed attributes refer to On Interval Inputs/Outputs.
Promises
Asynchronous operations in Functions are handled via Promises based on ES6 Promise standards. promise
is implicitly available to every Function.
const Promise = require('promise'); // No need to add this line
Learn more
Learn more about Promise and Promise.all()
Promise.all()
You can leverage the Promise.all() for parallel execution of multiple asynchronous functions.
Take the following example where we fetch a user name from the KV Store and fetch an IP address for that user from an external web service. When both are available (and not before), the logic to update the request object will execute.
export default (request) => {
const store = require('kvstore');
const xhr = require("xhr");
const fullName = store.get('fullName');
const ipAddress = xhr.fetch("https://httpbin.org/ip");
return Promise.all([fullName, ipAddress])
.then((values) => {
request.message.fullNameResult = values[0];
request.message.ip = JSON.parse(values[1].body).origin;
return request.ok();
})
show all 20 linesLibraries
The Functions runtime provides custom built-in libraries to support functionality not found natively as part of the JavaScript language.
Functions API
For more information about the Functions API, check out the Functions API documentation.
A library can be imported using the require()
method.
const xhr = require(xhr); // Example of importing a library
The following libraries are available in Functions:
Library Name | Description |
---|---|
XHR | The XHR library is used to enable the developer to send HTTP or HTTPS requests to a remote web server and load the response data back into a Function. This library is perfect for third-party authentication or triggering webhooks from a Function. |
KV Store | This library allows access to the KV store . It's a persistent key value store that acts as a database for your Functions . The KV store database is globally distributed and eventually consistent. Data in the KV store is shared at a subscribe key level. |
Advanced Math | Global (lat-long) coordinate and geometry functions. |
Crypto | The Crypto library provides encryption and decryption functionality in an Function. |
Utils | Simple utility functions that didn't belong anywhere else. |
Codec/auth | Provides an encoder for HTTP basic auth credentials. |
Codec/base64 | Provides an encoder and decoder for Base64 strings. |
Codec/query_string | Provides an encoder and decoder for URI query parameters. |
PubNub | The PubNub library allows you to leverage many of the client SDK features supported by the PubNub Platform. |
vault | Read-only database to retrieve secrets. |
Features not yet available in Functions
Some JavaScript features that you may expect to see, but aren't yet available in Functions:
- Native node modules
- async/await
- Access to process and some other global variables
- Ability to install third-party modules via npm
Webhooks On Request
You can use an on Request event type to create webhooks.
Let's take an example to learn how On Request can be used to create webhooks. Let's say that you want to check whether the given username already exists in the database or not. For this, let's assume that a username
is passed as a query parameter to the webhook.
-
The following code shows how you can extract the passed username from the query parameter and checks whether it already exists in the database or not.
show all 18 linesexport default (request, response) => {
const db = require('kvstore');
const username = request.params.username;
return db.get(username).then((dataFromDb) => {
if (!dataFromDb) {
console.log('The username does not exist.');
db.set(username, {});
response.status = 200;
return response.send('Username is available');
} else {
console.log('The username already exists.');
response.status = 409;
return response.send('Username already exists'); -
Click Save.
-
Click Restart Module.
We're done! You can test the function from the HTTP client on the left side.
Chaining
Functions can be linked to execute in sequential way or depending on a specific condition. It's done using the pubnub.publish()
, pubnub.signal()
or the pubnub.triggerRequestFunction()
methods. In the below examples, we have used pubnub.publish()
but the same is applicable to the other two methods.
Modules for chained functions
It's recommended that functions that you would like to chain with each other are in the same Module, so it's easier to start/stop their execution.
Chain Functions
Let's take an example, you want to capture a publish messages sent on hello-world, and send it to your hello-logger
function.
-
Create an On Before Publish or Fire "hello-logger" function:
export default (request) => {
console.log(request) // show what we have inside
return request.ok() // done
}; -
Create an On Before Publish or Fire
hello-world
functionexport default (request) => {
const pubnub = require('pubnub');
pubnub.publish({
"channel": "hello-logger",
"message":request.message
}).then((publishResponse) => {
console.log(`Publish Status: ${publishResponse[0]}:${publishResponse[1]} with TT ${publishResponse[2]}`);
}).catch((err) => {
console.error(err);
});
return request.ok(); // Return a promise when you're done
}; -
Click Save.
-
Click Restart Module.
-
Open a debug console tab on your browser to PubNub Debug Console.
-
Enter hello_world, hello-logger for the channel in the debug console.
-
Click Subscribe.
-
Back on the Functions screen, click Publish on the test payload.
Fork Functions
Let's take an example, you want to capture a publish messages sent on hello-world, edit the message to include "Hello": "World"
and would like to send the newer message to hello-universe channel along with the original hello-world channel.
-
Create a new Before Publish or Fire Function with:
show all 31 linesexport default (request) => {
const db = require('kvstore');
const pubnub = require('pubnub');
console.log('The message ', request.message, ' was published on ', request.channels[0], ' via ', request.meta.clientip);
request.message.hello = 'world!'; // augment hello = world
// To fork return pubnub.publish and include request.ok in the .then()
return pubnub.publish({
"channel": "hello_universe",
"message": request.message
}).then((publishResponse) => {
console.log(`Publish Status: ${publishResponse[0]}:${publishResponse[1]} with TT ${publishResponse[2]}`);
return request.ok(); -
Click Save.
-
Click Restart Module.
-
Open a debug console tab on your browser to PubNub Debug Console.
-
Enter hello-world, hello-universe for the channel in the debug console.
-
Click Subscribe.
-
Back on the Functions screen, click Publish on the test payload.
Avoid infinite loops: You can chain/fork publishes across as many channels as you wish, however it's important not to create a scenario where an infinite loop is possible (for example, publishing to A, which publishes to B, which Publishes back to A.) The system is designed to detect and not allow infinite loops to happen, however, it's important to take care that your logic also doesn't encourage or rely on this behavior.
Recursion limit
The maximum recursion limit you can do is 3
hops from one Function to another: using publish
or fire
, you can execute a maximum of three Functions.
The combined maximum number within a single Function execution of KV store
operations, XHRs
, publish
and fire
is 3
.
Request/Response Objects
All Event Types except On Request
request
Methods
Method | Arguments | Description |
---|---|---|
ok | message:String (Optional) | Returns a promise that resolves to the value of the request object. |
abort | message:String (Optional) | Returns a promise that resolves to the value of the request object, with an error code. |
request
Attributes
Attribute | Type | Definition |
---|---|---|
message | Object | The actual user message sent to the channel. |
verb | String | Method used by the publishing client when sending the message to PubNub. |
pubkey | String | The Publish Key used when sending the message. |
subkey | String | The Subscribe Key to retrieve the message. |
channels | Array<String> | The list of channels on which the message was sent on. |
version | String | API Version. |
meta.clientip | String | IP of the publishing client. |
meta.origin | String | Origin defined on the publishing client. |
meta.useragent | String | The Publishing client's useragent string. |
params | Object | URL Parameters made on the request. |
uri | String | The URI of the request. |
On Request Inputs/Outputs
request
Attributes
Attribute | Type | Definition |
---|---|---|
verb | String | Method used by the publishing client when sending the message to PubNub. Always set to rest . |
pubkey | String | The Publish Key used when sending the message. |
subkey | String | The Subscribe Key to retrieve the message. |
version | String | API Version. |
meta.clientip | String | IP of the publishing client. |
meta.origin | String | Origin defined on the publishing client. |
meta.useragent | String | The Publishing client's useragent string. |
params | Object | URL Parameters made on the request. |
uri | String | The full path of the URI of the request minus PubNub hostname information. |
path | String | The path minus PubNub and key specific information. This is the path configured, by you, for the Function itself. |
method | String | The HTTP method of the request, such as GET, PUT, POST, DELETE. |
body | Object | The body content if passed in the request. |
headers | Object | The header information passed in the request. |
response
Methods
Method | Arguments | Description |
---|---|---|
send | body:String (Optional) | Returns a promise that resolves to the value of the response object. |
response
Attributes
Attribute | Type | Definition |
---|---|---|
status | Object | The HTTP status code to use when returning the response to the calling application or user. |
body | Object | The body content returned to the calling application or user. |
headers | Object | Header information returned to the calling application or user. |
On Interval Inputs/Outputs
event
Methods
Method | Arguments | Description |
---|---|---|
ok | N/A | Returns a promise that resolves to the value of the response object. |
event
Attributes
Attribute | Type | Definition |
---|---|---|
verb | String | Method used by the publishing client when sending the message to PubNub. Always set to interval . |
pubkey | String | The Publish Key used when sending the message. |
subkey | String | The Subscribe Key to retrieve the message. |
execInterval | Number | Duration of the interval specified for the function, in milliseconds. |
lastTimestamp | Number | Timestamp of last function execution. |
timestamp | Number | Timestamp of current function execution. |
Subscribe On Interval Inputs/Outputs
event
Methods
Method | Arguments | Description |
---|---|---|
ok | N/A | Returns a promise that resolves to the value of the response object. |
event
Attributes
Attribute | Type | Definition |
---|---|---|
verb | String | Method used by the publishing client when sending the message to PubNub. Always set to interval . |
pubkey | String | The Publish Key used when sending the message. |
subkey | String | The Subscribe Key to retrieve the message. |
execInterval | Number | Duration of the interval specified for the function, in milliseconds. |
lastTimestamp | Number | Timestamp of last function execution. |
timestamp | Number | Timestamp of current function execution. |
Create a Function
Follow these instructions to create a function.
Hello World
You'll need to create a module before you can create a function. A module is a collection of Functions. Modules are useful to start and stop a set of functions together.
-
Log into the Admin Portal, go to the Functions page -> Create New Module -> Create New Function -> select the Before Publish or Fire function event type. Different event types are listed in Event Types.
-
Configure the function to trigger on a channel by specifying a channel name, 'hello-world'. Then Save.
-
A sample function will be automatically added to get you started. You can update the code to include some simple logging to see how it works.
export default (request) => {
console.log('request', request);
request.message.hello = 'world!'; // augment hello = world
console.log('The message: ', request.message, ' was published on ', request.channels[0], ' via', request.meta.clientip);
return request.ok(); // Return a promise when you're done
} -
Click Save Function on the left panel.
Run & Test
- Start the Module.
- Click on the Publish button of the Test payload to see it in action.
Trigger Functions
A Function is triggered on one or more channels, except for the case of an OnRequest Function, in which triggering occurs through a HTTP API request. Clients that are publishing and subscribing to a channel have no awareness of which (if any) Functions are configured against the messages they send and receive. Execution of Function only occurs when the parent Module is running.
Starting a Module
You can start a Module by clicking on the Start Module button at the top right of the Functions screen.
When you click the Start Module button, the latest saved version of each Function in the Module is scheduled to start. This should occur within several seconds. To ensure you're running the latest version of your code, click the Save button before you start a Module.
When the Module starts, each Function of the Module runs on all the data centers of the PubNub Network until the Module is stopped. To achieve superior performance and the lowest latencies possible, all functions run hot.
When the Module starts, each Function of the Module runs on all the data centers of the PubNub Network.
Stopping a Module
A Module is stopped by clicking the Stop Module button displayed at the top right of the Functions screen.
When the Module is stopped, all Functions in the Module are stopped. Messages will pass through the PubNub network without triggering your saved Functions. Web API calls made to On Request Functions will result in a 404 Not Found error.
Module States
Below is the list of states that the Module can be in:
State | Definition |
---|---|
Stopped | None of the Functions in the Module are running. Messages will pass through the PubNub network without triggering your saved Functions. |
Running | All Functions in the Module are running and operational. |
Pending | The Functions in the Module are being started. This is a transient state, and the Module may remain in this state for up to 20 seconds. |
Stopping | The Module is being stopped. Like the Pending state, this is a transient state, and the Module may remain in the Stopping state for few seconds. |
Failed | One or more Functions in the Module failed to run because of an error, and all functions are stopped. Check the logs for more information. |