Functions Development Guidelines

Functions modules and API

For more information about the available Functions modules or the public REST API (for Functions v2) you can work with directly, check out the Functions Modules or REST 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 modules 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(). The 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 called json(), and the 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 called 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 for 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 Promise.all() for parallel execution of multiple asynchronous Functions.

Take the following example where we fetch a username 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 be executed.

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 lines

Modules

You can use modules with your Functions to optimize their performance and provide specialized functionality for specific tasks. This allows each Function to be more efficient and tailored to the particular event it handles.

For the full list of modules supported by PubNub Functions, refer to Functions modules.

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.

  1. 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.

    export 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');
    show all 18 lines
  2. Save the changes and, depending on the Functions version you use (v1 or v2), either restart the module

    Module

    A collection of Functions (v1) used to manage and control a set of Functions.
    or confirm creating a new Package

    Package

    A collection of Functions (v2) used to manage and control a set of Functions.
    Revision and deploy it.

We're done! You can now test the Function.

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 use pubnub.publish(), but the same is applicable to the other two methods.

Modules/Packages for chained Functions

It's recommended that Functions that you would like to chain with each other are in the same Module/Package, 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 the hello-world channel, and send it to your hello-logger Function.

  1. 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
    };
  2. Create an On Before Publish or Fire hello-world Function:

    export 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
    };
  3. Save the changes and, depending on the Functions version you use (v1 or v2), either restart the Module or confirm creating a new Package Revision and deploy it.

  4. Open a debug console tab on your browser to PubNub Debug Console.

  5. Enter hello_world, hello-logger for the channel in the debug console.

  6. Click Subscribe.

  7. Back on the Functions screen, publish the test payload.

Fork Functions

Let's take an example where you want to capture a publish messages sent on hello-world, edit the message to include "Hello": "World" and send the newer message to the hello-universe channel along with the original hello-world channel.

  1. Create a new Before Publish or Fire Function:

    export 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();
    show all 31 lines
  2. Save the changes and, depending on the version of Functions you use (v1 or v2), either restart the Module or confirm creating a new Package Revision and deploy it.

  3. Open a debug console tab on your browser to PubNub Debug Console.

  4. Enter hello-world, hello-universe for the channel in the debug console.

  5. Click Subscribe.

  6. Back on the Functions screen, publish 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, check that your logic 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

MethodArgumentsDescription
okmessage:String (Optional)Returns a promise that resolves to the value of the request object.
abortmessage:String (Optional)Returns a promise that resolves to the value of the request object, with an error code.

request Attributes

AttributeTypeDefinition
messageObjectThe actual user message sent to the channel.
verbStringMethod used by the publishing client when sending the message to PubNub.
pubkeyStringThe Publish Key used when sending the message.
subkeyStringThe Subscribe Key to retrieve the message.
channelsArray<String>The list of channels on which the message was sent on.
versionStringAPI Version.
meta.clientipStringIP of the publishing client.
meta.originStringOrigin defined on the publishing client.
meta.useragentStringThe Publishing client's useragent string.
paramsObjectURL Parameters made on the request.
uriStringThe URI of the request.

On Request Inputs/Outputs

request Attributes

AttributeTypeDefinition
verbStringMethod used by the publishing client when sending the message to PubNub. Always set to rest.
pubkeyStringThe Publish Key used when sending the message.
subkeyStringThe Subscribe Key to retrieve the message.
versionStringAPI Version.
meta.clientipStringIP of the publishing client.
meta.originStringOrigin defined on the publishing client.
meta.useragentStringThe Publishing client's useragent string.
paramsObjectURL Parameters made on the request.
uriStringThe full path of the URI of the request minus PubNub hostname information.
pathStringThe path minus PubNub and key specific information. This is the path configured, by you, for the Function itself.
methodStringThe HTTP method of the request, such as GET, PUT, POST, DELETE.
bodyObjectThe body content if passed in the request.
headersObjectThe header information passed in the request.

response Methods

MethodArgumentsDescription
sendbody:String (Optional)Returns a promise that resolves to the value of the response object.
response Attributes
AttributeTypeDefinition
statusObjectThe HTTP status code to use when returning the response to the calling application or user.
bodyObjectThe body content returned to the calling application or user.
headersObjectHeader information returned to the calling application or user.

On Interval Inputs/Outputs

event Methods

MethodArgumentsDescription
okN/AReturns a promise that resolves to the value of the response object.

event Attributes

AttributeTypeDefinition
verbStringMethod used by the publishing client when sending the message to PubNub. Always set to interval.
pubkeyStringThe Publish Key used when sending the message.
subkeyStringThe Subscribe Key to retrieve the message.
execIntervalNumberDuration of the interval specified for the Function, in milliseconds.
lastTimestampNumberTimestamp of last Function execution.
timestampNumberTimestamp of current Function execution.

Subscribe On Interval Inputs/Outputs

event Methods

MethodArgumentsDescription
okN/AReturns a promise that resolves to the value of the response object.

event Attributes

AttributeTypeDefinition
verbStringMethod used by the publishing client when sending the message to PubNub. Always set to interval.
pubkeyStringThe Publish Key used when sending the message.
subkeyStringThe Subscribe Key to retrieve the message.
execIntervalNumberDuration of the interval specified for the Function, in milliseconds.
lastTimestampNumberTimestamp of last Function execution.
timestampNumberTimestamp of current Function execution.

Create a Function

This short instruction shows how to create a simple Function on the Admin Portal. This Function changes the content of the message before publishing it on the previously specified channel.

Admin Portal UI

This section shows how to use Admin Portal to create PubNub Functions. To familiarize yourself with the UI for Functions, go to the Functions v2 section of the Admin Portal documentation.

Set up configuration

You'll need to create a Package

Package

A collection of Functions (v2) used to manage and control a set of Functions.
before you can create a Function.

  1. Log into the Admin Portal and go to the Functions v2 section.

  2. Create a Package.

    Click Create package. Choose to Configure your own Package and fill in the Package name and description. Confirm the changes by clicking Next.

  3. Create a Function.

    Add a Function name and select the Before Publish or Fire event type. Configure the Function to trigger on a channel by specifying a channel name as hello-world. Confirm the changes by clicking Create package.

  4. Open the new Package to see the initial Revision that was created for it. To edit the Function's code, either click the Edit code button or Edit Latest on the Package Revision list view.

  5. As you can see in the editor, a sample Function is automatically added to the Function's toolbox to help you get started. You can replace the code to include some simple logging and 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
    }
  6. Click Save at the top. As you can see, changing the Function's code generates a new Revision for it. Fill in the Revision name and description and save the changes.

  7. To deploy the Package Revision with the Function, click Deploy.

  8. Select Add keyset, to point to all the keyset(s) you want the Function to run on. Confirm the changes by clicking Create.

  9. Since you're not assigning any secrets for the purpose of this example, just confirm by clicking Deploy again and creating the actual deployment of the Function.

Maximum number of deployments

The number of deployments is equal to the number of keysets you selected for the Package Revision to run on. The maximum number of keysets that a Package Revision can run on is 50.

Run and test

To test the new Function, follow these steps:

  1. Open the Function's editor either by clicking the Edit code button or Edit Latest on the Package Revision list view.
  2. Switch to the Debug tab.
  3. Click the Publish button in the Test payload section to see the Function in action.

Trigger Functions

A Function is triggered on one or more channels (through wildcards), except for the case of an On Request Function, in which triggering occurs through an 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 a Function only occurs when the parent Package Revision (version of a Package with Functions) is running.

Start a Module/Package

You can start a given Package Revision by clicking the start button next to a given Revision on the Package Revision list view.

When the Package Revision starts, each Function in a given Package Revision runs on all the data centers of the PubNub Network until the Package Revision is stopped. To achieve superior performance and the lowest latencies possible, all Functions run hot. This means that they are all ready to process incoming request rather than forcing Functions into a resource-saving mode if they do not receive traffic for some time.

When the Package Revision starts, each Function of the Package Revision runs on all the data centers of the PubNub Network.

Stop a Module/Package

A Package Revision is stopped by clicking the stop button next to a given Revision on the Package Revision list view.

When the Package Revision is stopped, all Functions in the Package Revision 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.

Last updated on