Programming Model

Fusebit functions are lightweight and stateless pieces of Node.js code that execute as a result of a request from your application backend, or based on a cron schedule. Functions are packaged as Node.js modules, which makes them easy to manage and distribute. At its most basic, a function looks like this:

module.exports = async (ctx) => {
  return { body: 'Hello world!' };
};

The interface returns the result (as specified below) directly or a properly formed Promise, and indicates an error by throwing an exception:

module.exports = async (ctx) => {
  throw new Error('Failure');
};

Context object

The function receives incoming parameters through the ctx object.

The ctx parameter contains useful information about the invocation of the function:

  • accountId - your Fusebit account id
  • subscriptionId - your Fusebit subscription id
  • boundaryId - the id of the Fusebit boundary, which this function is a part of
  • functionId - the id of the Fusebit function being executed
  • configuration - an object containing any application settings and secrets you specify
  • method - the method of invocation for this incoming call
    • GET, POST, PUT, DELETE and other HTTP methods
    • CRON in case the function was invoked on a schedule by the Fusebit cron service
  • baseUrl - (only for non-scheduled invocations) the function base URL, for example https://stage.us-west-2.fusebit.io/v1/run/sub-ab9d9113ea353241/my-boundary/my-function
  • url - (only for non-scheduled invocations) the request URL, including the path and query parameters, for example /run/sub-ab9d9113ea353241/my-boundary/my-function/foo/bar?abc=def
  • path - (only for non-scheduled invocations) the request path, which is the part of the url following the baseUrl, and excluding query parameters, for example /foo/bar
  • query - (only for non-scheduled invocations) an object representing the request query string
  • headers - (only for non-scheduled invocations) an object representing the request headers
  • body - (only for non-scheduled invocations) an object representing the request body
  • fusebit.functionAccessToken - an access token to Fusebit APIs supplied to the function by the Fusebit Platform following the parameters in the function specification.
  • fusebit.caller.permissions and fusebit.caller.accessToken - authenticated and authorized caller's permissions and access token, depending on the security requirements in the function specification.

Result object

The function is expected to return, either as the second parameter in the callback or as the return value of the asynchronous function, an object with the following properties:

  • status (optional; default: 200) - set that to the HTTP status code you would like to return with your response
  • body (optional) - the JSON you would like to return with your response
  • bodyEncoding (optional; default: application/json) - specifies the format that the body parameter should be considered.
  • headers (optional) - specifies additional headers to include in the HTTP response

If no response at all is provided, then a 200 OK response is generated with a 0 length body payload. Otherwise, the default behavior encodes a body as JSON. If HTML is desired, it is very easy to encode body as a base64 encoded string:

module.exports = async (ctx) => {
  return html('<b>Hello</b> World');
};

function html(body, headers, options) {
  return {
    ...options,
    headers: {
      ...headers,
      'Content-Type': 'text/html',
    },
    bodyEncoding: 'base64',
    body: Buffer.from(body).toString('base64'),
  };
}

Callback interface

A callback-based interface is also offered, which exposes following signature to the Fusebit framework:

module.exports = (ctx, cb) => {
  cb(null, { body: 'result' });
};

Upon completion, the cb(error, result) callback is invoked, passing an Error as the first parameter and result, as specified above, as the second.

  • If your function completes successfully, set the error parameter to null so your callback looks like this: cb(null, { body: 'Hello world!' });. This will result in a HTTP 200 response with JSON in body of the response.
  • If your function encounters an error, set the error parameter and omit the second parameter. Your callback will look like this: cb(new Error('Something went wrong!'));. This will result in a HTTP 500 response with the error serialized as JSON in the body of the response.
  • Failing to call cb from inside your function will result in it being terminated after a timeout period.
  • The return value of the traditional callback interface is ignored.

Using NPM packages

Fusebit allows use of any public npm package. Add the reference to the package you need in package.json as you normally would during Node.js development, more details here. This can be done via the built-in Fusebit editor, the CLI, or via API. For example:

{
  "dependencies": { "is-thirteen": "*" }
}

Then, reference and use the module in your function:

const is = require('is-thirteen');

module.exports = async (ctx) => {
  return { body: is(13).thirteen() };
};

Application settings

Frequently, you want to keep certain application settings and secrets outside of the code of your function. Fusebit provides a dedicated feature for this, which also ensures they are safely encrypted at rest. To access these settings via the editor go to Settings > Application in the nav bar. Settings are simply key/value pairs like so

API_KEY=KMQCHHWL8tNwTXzHjpViC)Mz

You can reference this value from with the code of your function via ctx.configuration.API_KEY.

Scheduled execution

Sometimes you need a Fusebit function to execute on a pre-set scheduled cadence, as opposed to in response to a request from your application. The Fusebit cron service enables you to easily set that up. Enabling and configuring scheduled executions can be done in the Fusebit editor by going to Settings > Schedule. You can then specify your preferred execution schedule in standard cron format. For example, specifying the following will cause your function to execute every day at 5AM UTC time.

cron=0 5 * * *

If you would like to specify the schedule relative to a different timezone, you can do so as follows (list of timezone identifiers is available here):

timezone=US/Pacific
cron=0 22 * * Fri

The above will cause your function to execute at 10pm every Friday, US Pacific time. To disable scheduled execution, simply clear or comment out the above and hit Save.

Sometimes you may want to secure a scheduled function so it can only be called by the cron service, and not by an external HTTP request. That is easy to accomplish using the following pattern

module.exports = async (ctx) => {
  if (ctx.method !== 'CRON') {
    throw new Error('Not authorized');
  }

  // Code here can only be invoked by cron
};

Custom programming models

In some cases, the default function signature described so far in this document may not be the best fit for your scenario. For example, if the function is being invoked in the context of a lead generation workflow, you may wish to surface a more structured programming interface, for example:

module.exports = (lead) => {
  if (lead.value > 5000) {
    lead.status = 'VIP';
  } else {
    throw new Error('Not a VIP!');
  }
};

Note how in this example, the generic ctx context object has been replaced by a more tailored lead object, and the callback model has been simplified. This can be accomplished in Fusebit following a few easy steps:

  1. Create a new file in the Fusebit editor for the specialized interface (let's assume onNewLead.js in the above example)

  2. In the index.js file, transform the incoming data and call onNewLead.js:

    const onNewLead = require('./onNewLead.js');
    
    module.exports = async (ctx) => {
      return onNewLead(ctx.body, ctx.configuration);
    };
    
  3. Since the index.js file is no longer relevant to your end users, you can hide it from the Fusebit editor. When calling the createEditor method in your client application, pass the following to the editor property:

    {
      "navigationPanel": {
        "hideFiles": ["index.js"]
      }
    }