# Code Step Overview

The [code component](https://prismatic.io/docs/components/code.md) allows you to execute product or industry-specific code within an integration. This page outlines when and how to use a code component.

## Why use the code component?[​](#why-use-the-code-component "Direct link to Why use the code component?")

You will likely have integration logic that can't be solved using the [standard components](https://prismatic.io/docs/components.md) Prismatic provides. The portion of your integrations that are specific to your product or industry can be accomplished using code component steps or [custom components](https://prismatic.io/docs/custom-connectors.md).

## Code component vs custom connector[​](#code-component-vs-custom-connector "Direct link to Code component vs custom connector")

Generally, the code component is useful if:

* Your code does not depend on external libraries
* Your code is short and succinct
* Your code is step-specific and not reusable elsewhere

You should consider building a [custom connector](https://prismatic.io/docs/custom-connectors.md) if:

* Your code relies on external libraries
* You would like to unit test your code independent of your integration
* Your code is reusable and could be duplicated in multiple flows or integrations

## Adding a code step to an integration[​](#adding-a-code-step-to-an-integration "Direct link to Adding a code step to an integration")

Within the integration designer, [add a step](https://prismatic.io/docs/integrations/low-code-integration-designer/steps.md#adding-steps-to-integrations) to your integration. Select the **Code** component, **Code Block** action.

A new code step appears in your integration. Click the **Edit** button to open the code editor:

![Code editor in Prismatic app](/docs/assets/images/code-step-f079f39f5d8f2d4416015296d23555d9.png)

## Code structure[​](#code-structure "Direct link to Code structure")

The code component provides a stub function by default. Let's examine the structure of the code:

```javascript
module.exports = async ({ logger, configVars }, stepResults) => {
  return { data: null };
};

```

You must export an asynchronous function. The default code uses [arrow function notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) to create an `async` function to return.

## Code component parameters[​](#code-component-parameters "Direct link to Code component parameters")

This function is provided a few parameters:

1. The first positional parameter is comprised of several properties:

   <!-- -->

   * `logger` allows you to write out log lines.
   * `debug` is an object which you can use when [debug mode](https://prismatic.io/docs/integrations/troubleshooting.md#debug-mode) is enabled to emit additional debug log lines or measure time or memory costs of specific portions of your code.
   * `configVars` lets you access config variables (including connections).
   * `instanceState`, `crossFlowState`, `integrationState`, and `executionState` give you access to [persisted state](https://prismatic.io/docs/custom-connectors/actions.md#execution-instance-and-cross-flow-state).
   * `stepId` is the ID of the current step being executed.
   * `executionId` is the ID of the current execution.
   * `webhookUrls` contains the URLs of the running instance's sibling flows.
   * `webhookApiKeys` contains the API keys of the running instance's sibling flows.
   * `invokeUrl` was the URL used to invoke the integration.
   * `customer` is an object containing an `id`, `name`, and `externalId` of the customer the instance is assigned to.
   * `user` is an object containing an `id`, `name`, `email` (their ID), and `externalId` of the customer user whose user-level configuration was used for this execution. This only applies to instances with [User Level Configuration](https://prismatic.io/docs/integrations/config-wizard/user-level-configuration.md).
   * `integration` is an object containing an `id`, `name`, and `versionSequenceId` of the integration the instance was created from.
   * `instance` is an object containing an `id` and `name` of the running instance.
   * `flow` is an object containing the `id` and `name` of the running flow.

2. The second positional parameter, `stepResults`, is an object that contains output from previous steps of the integration.

### Logging[​](#logging "Direct link to Logging")

`context.logger` is an object that can be used for logging and debugging. `context.logger` has four functions: `debug`, `info`, `warn`, and `error`. For example:

```javascript
module.exports = async (context, stepResults) => {
  context.logger.info("Things are going great");
  context.logger.warn("Now less great...");
};

// or

module.exports = async ({ logger }, stepResults) => {
  logger.info("Hello World");
};

```

**Note**: Log lines are truncated after 4096 characters. If you need longer log lines, consider [streaming logs](https://prismatic.io/docs/monitor-instances/logging/streaming-logs-externally.md) to an external log service.

### Config variables[​](#config-variables "Direct link to Config variables")

`context.configVars` provides the [Code Component](https://prismatic.io/docs/components/code.md) with access to all [config variables](https://prismatic.io/docs/integrations/config-wizard/config-variables.md), including connections, associated with the integration.

If you have a config variable named `Acme ERP Base URL`, for example, you could reference that config variable in a code step with `context.configVars["Config Variable Name"]` syntax:

```javascript
module.exports = async ({ configVars }, stepResults) => {
  const fuelApiUrl = `${configVars["Acme ERP Base URL"]}/fuel`;
  // ...
};

```

### Connections[​](#connections "Direct link to Connections")

[Connections](https://prismatic.io/docs/integrations/connections.md) are a special type of config variable. You can access the contents of a connection the same way that you would any other config variable. In this example, suppose you have a connection config variable named `Acme ERP Connection` that contains two fields, `tenantId` and `apiKey`:

Destructuring a connection config variable

```javascript
module.exports = async ({ logger, configVars }, stepResults) => {
  const {
    fields: { tenantId, apiKey },
  } = configVars["Acme ERP Connection"];
  const result = await doAThing({ tenantId, apiKey });
  return { data: result };
};

```

## Referencing previous step outputs[​](#referencing-previous-step-outputs "Direct link to Referencing previous step outputs")

Most steps of an integration return some sort of value. An **HTTP - GET** action, for example, might return a JSON payload from a REST API. An **Amazon S3 - Get Object** will return a binary file pulled from S3.

The code component can reference those outputs through the `stepResults` parameter. `stepResults` is an object that contains results from all previous steps.

For example, if you have an **HTTP - GET** step named **Fetch Users List** that pulls down an array of users from <https://jsonplaceholder.typicode.com/users>, you can generate an array of email addresses with this code:

```javascript
module.exports = async (context, stepResults) => {
  const userArray = stepResults.fetchUsersList.results;
  const emailArray = userArray.map((user) => user.email);
  return { data: emailArray };
};

```

Step results are often objects

Many components return objects that have multiple keys. So, you can reference `stepResults.myStepName.results.someKey`. It's rare for a component to return serialized JSON, so there's rarely need to `JSON.parse()` results from a previous step.

### Previous step names as variables[​](#previous-step-names-as-variables "Direct link to Previous step names as variables")

Since names of steps can include spaces and non-JavaScript-friendly characters, alphanumeric characters of step names are converted to camelCase. So, a step named **Download JSON from API** would be converted to **downloadJsonFromApi**. You can test out step name to referenceable name conversions here:

Step Name

Download JSON from API

Step Name

Reference Name / Step ID

Reference Name / Step ID

### Referencing integration trigger payload data[​](#referencing-integration-trigger-payload-data "Direct link to Referencing integration trigger payload data")

The integration trigger is another step that can have a unique name. Suppose an integration is triggered by a webhook, the trigger is named `My Integration Trigger`, and the webhook is provided a payload `body.data` of `{"exampleKey": "exampleValue"}`.

![Reference integration trigger payload in Prismatic app](/docs/assets/images/trigger-payload-a34699b9d9f798a16a7d6416099f9a12.png)

That `exampleKey` would be accessible using `stepResults.myIntegrationTrigger` like so:

```javascript
module.exports = async ({ logger }, stepResults) => {
  const exampleKey =
    stepResults.myIntegrationTrigger.results.body.data.exampleKey;
  logger.info(`Received '${exampleKey}'`);
};

```

Using JavaScript destructuring, you can instead write this:

```javascript
module.exports = async (
  { logger },
  {
    myIntegrationTrigger: {
      results: {
        body: {
          data: { exampleKey },
        },
      },
    },
  },
) => {
  logger.info(`Received '${exampleKey}'`);
};

```

Notice the logged message in the testing drawer:

![Test runner step results in Prismatic app](/docs/assets/images/using-stepresults-99620a74473761fa61bc32577cecea88.png)

## Persisted data in a code step[​](#persisted-data-in-a-code-step "Direct link to Persisted data in a code step")

Like a custom component, a code step can save and reference [persisted state](https://prismatic.io/docs/custom-connectors/actions.md#execution-instance-and-cross-flow-state) at the flow (`instanceState`), cross-flow (`crossFlowState`), integration (`integrationState`), or execution (`executionState`) level.

To save a value `bar` as key `foo` at the `executionState` level:

```javascript
module.exports = async ({ logger, configVars }, stepResults) => {
  return {
    data: null,
    executionState: { foo: "bar" },
  };
};

```

To load the value of the key `foo` at the execution level, you can reference your function's first parameter's `executionState` property:

```javascript
module.exports = async ({ executionState }, stepResults) => {
  const myvalue = executionState["foo"];
  return { data: `My value is ${myvalue}` };
};

```

## Code component return values[​](#code-component-return-values "Direct link to Code component return values")

The code component can optionally return a value for use by a subsequent step. The return value can be an object, string, integer, etc., and will retain its type as the value is passed to the next step.

The return value is specified using the `data` key in the return object.

In this example, we return a string with value `"https://ipinfo.io/ip"`:

```javascript
module.exports = async (context, stepResults) => {
  return { data: "https://ipinfo.io/ip" };
};

```

The output can be used as input for the next step by referencing `codeComponentStepName.results`.

![Use output for prior step for input to new step in Prismatic app](/docs/assets/images/return-values-4804dc7a4da4c9754651d60c6c6dbbbe.png)

To see an example of returning more complex data structures, and a good example use case for a code component, see the [Using a Code Component to Transform Data](https://prismatic.io/docs/integrations/low-code-integration-designer/code-step/code-component-to-transform-data.md) quickstart.

### Returning binary data from a code step[​](#returning-binary-data-from-a-code-step "Direct link to Returning binary data from a code step")

Sometimes you'll want your code component to return binary data (like a rendered image or PDF). To do that, return an object with a `data` property of type `Buffer` (a file buffer), and a `contentType` property of type `String` that contains the file's [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types):

```javascript
module.exports = async (context, stepResults) => {
  // ...
  const fileBuffer = SomePdfLibrary.generatePdf();
  return {
    data: fileBuffer,
    contentType: "application/pdf",
  };
};

```

To see an example use case for returning binary data from a code component, check out our [Generate a PDF with a Code Component](https://prismatic.io/docs/integrations/low-code-integration-designer/code-step/generating-a-pdf-with-a-code-component.md).

**For More Information**: [Using a Code Component to Transform Data](https://prismatic.io/docs/integrations/low-code-integration-designer/code-step/code-component-to-transform-data.md)

## Making HTTP calls from a code step[​](#making-http-calls-from-a-code-step "Direct link to Making HTTP calls from a code step")

The [fetch](https://developer.mozilla.org/en-US/docs/Web/API/fetch) API is baked into the code component. To make an HTTP call to an API, you can use the `fetch` function:

Make an HTTP POST request from a code step

```javascript
module.exports = async (context, stepResults) => {
  const options = {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
      Authorization: "Bearer abc-123",
    },
    body: JSON.stringify({ foo: "bar", baz: 123 }),
  };
  const response = await fetch("https://postman-echo.com/post", options);
  const jsonData = await response.json();
  return { data: jsonData };
};

```

## Adding dependencies to a code step[​](#adding-dependencies-to-a-code-step "Direct link to Adding dependencies to a code step")

If your code component depends on node modules from `npm`, dependencies will be dynamically imported from the [UNPKG](https://unpkg.com/) and [jsDelivr](https://www.jsdelivr.com/) CDNs. For example, if your code component reads:

Import lodash as a dependency

```javascript
const lodash = require("lodash@4.17.21/lodash.js");

module.exports = async (context, stepResults) => {
  const mergedData = lodash.merge(
    { cpp: "12" },
    { cpp: "23" },
    { java: "23" },
    { python: "35" },
  );
  return { data: mergedData };
};

```

Then [lodash](https://unpkg.com/browse/lodash@4.17.21/lodash.js) version 4.17.21 will be imported as a dependency.

You should specify specific known working versions of `npm` packages for your code component:

```javascript
const lodash = require("lodash@2.4.2");
const { PDFDocument } = require("pdf-lib@1.17.1/dist/pdf-lib.js");

```

You can require any file from `npm` using `package[@version][/file]` syntax. Note that with the `lodash` import above, no file was specified. If no file is specified, the `main` file defined in the `npm` package's `package.json` is imported. An explicit path was called out for the `pdf-lib` import because the `pdf-lib` package defaults to importing an index file that itself requires other files, and `dist/pdf-lib.js` is a completely independent file that can be imported on its own..

Downstream dependencies

In order for an external dependency to be compatible with a code step, all JavaScript code must be compiled into a single file.

For example, <https://unpkg.com/lodash@4.17.20/lodash.js> contains all of the code necessary to run in a single file. <https://app.unpkg.com/lodash@4.17.20/files/flatten.js> does not - it has its own `require()` statement and depends on other files. The former would work in the code step, the latter would not.

If the external package has its own dependencies that are not compiled in, or if the file you reference has its own `require()` statements, you will see errors.

CDN outages can cause downtime

When a `require()` line is encountered in a code step, the code step will attempt to download the dependency from the UNPKG CDN. If UNPKG is down or otherwise unavailable, the code step will fall back to downloading the dependency from the jsDelivr CDN. If both CDNs are down, your code step will error.

If you need external dependencies, we strongly recommend using a code step for prototyping, but building a [custom component](https://prismatic.io/docs/custom-connectors.md) for production use. Custom components have their dependencies compiled in, and are not dependent on the uptime of an external CDN.

### Requiring built-in NodeJS modules[​](#requiring-built-in-nodejs-modules "Direct link to Requiring built-in NodeJS modules")

You can also require built-in NodeJS modules, like `crypto` or `path`. If the library you specify is built in to NodeJS, the client will *not* reach out to a CDN, and will instead use the built-in module.

```javascript
const crypto = require("crypto");

module.exports = async () => {
  const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
    modulusLength: 4096,
    publicKeyEncoding: {
      type: "spki",
      format: "pem",
    },
    privateKeyEncoding: {
      type: "pkcs8",
      format: "pem",
      cipher: "aes-256-cbc",
      passphrase: "top secret",
    },
  });

  return {
    data: {
      publicKey,
      privateKey,
    },
  };
};

```

## Using spectral utility functions in a code step[​](#using-spectral-utility-functions-in-a-code-step "Direct link to Using spectral utility functions in a code step")

Prismatic's SDK, [@prismatic-io/spectral](https://www.npmjs.com/package/@prismatic-io/spectral) is automatically imported into each code block as `spectral`. You can reference any utility functions that Spectral declares.

For example, if you need to cast a truthy `"NO"` string to a boolean, you can do this:

```javascript
module.exports = async ({ configVars }, stepResults) => {
  const doAThing = spectral.util.types.toBool(configVars["Do a Thing?"]);
  if (doAThing) {
    return "Did a thing";
  } else {
    return "Didn't do a thing";
  }
};

```

A list of all util type functions is available in the [Spectral SDK](https://github.com/prismatic-io/spectral/blob/main/packages/spectral/src/util.ts).
