JavaScript

The javascript function type allows you to write custom JavaScript or TypeScript code to implement integration logic.

Examples

When used in Membrane Interfaces definitions, the code of the function is provided as code property of the interface configuration.

For example, here is how Javascript function is used inside an Action definition:

name: Create Task
key: create-task
type: run-javascript
config:
  code: |-
    module.exports = async function({input, externalApiClient}) {
       const responseData = await externalApiClient.post('tasks', input)
       return responseData.id
    }

Javascript functions in connectors

When using in connector interfaces such as Authentication or Data Collections, Javascript functions are stored in separate .js or .ts files with a name matching the function name: <method-name>.js.

For example, refresh-credentials function of the Authentication interface would be located in auth/refrehs-credentials.js file.

Arguments

JavaScript implementations always receive the following input parameters, in addition to method-specific ones:

  • externalApiClient – API client configured with authentication that can be used to make requests to the external API. This parameter is available when code is executed in a context of a specific Connection.
  • internalApiClient - API client configured to make requests to your product's API (also called Internal API). This client is only available in the context of App Data Schemas at the moment.
  • credentials – authentication credentials for the current connection.
  • ... any additional arguments available to the function that is being implemented.

All the arguments are provided as properties of a single object that is passed as the function's first argument:

module.exports = async function({externalApiClient, internalApiClient, credentials, input}) {
  // Do something
}

Logging

You can log messages to the console using the console.log function:

console.log('Fetching items...')

To log a JSON object, you need to stringify it:

console.log(JSON.stringify(data))

API Clients

JavaScript method implementations receive API client(s) named externalApiClient and/or internalApiClient as arguments. They can be used to make API requests to an external API (based on the current integration or connection) and internal API (API of your product). The API client is automatically configured with authentication and base URL settings from the connector configuration - you don't need to provide authentication parameters into each request.

Making Requests

The API client provides methods for making HTTP requests:

interface ApiClient {
  // GET request with optional query parameters
  get(path: string, query?: Record<string, any>, options?: RestApiClientOptions): Promise<any>

  // POST request with data
  post(path: string, data?: any, options?: RestApiClientOptions): Promise<any>

  // PUT request with data
  put(path: string, data?: any, options?: RestApiClientOptions): Promise<any>

  // PATCH request with data
  patch(path: string, data?: any, options?: RestApiClientOptions): Promise<any>

  // DELETE request with optional data
  delete(path: string, data?: any, options?: RestApiClientOptions): Promise<any>
}

Examples

// GET request with query parameters
const response = await apiClient.get('/items', {
  page: 1,
  limit: 10
})

// POST request with data
const newItem = await apiClient.post('/items', {
  name: 'New Item',
  description: 'Description'
})

// PUT request to update
await apiClient.put('/items/123', {
  name: 'Updated Item'
})

// DELETE request
await apiClient.delete('/items/123')

Request Options

Each request method accepts an optional options parameter that can override the default client configuration:

interface RestApiClientOptions {
  // Base URI for relative paths
  baseUri?: string

  // Headers to add to the request
  headers?: Record<string, string>

  // Query parameters to add to all requests
  query?: Record<string, string>

  // Basic auth credentials
  auth?: {
    username: string
    password: string
  }

  // Return full response instead of just data
  returnFullResponse?: boolean

  // Response type - how to parse the response
  responseType?: 'json' | 'arraybuffer' | 'stream'
}

Example with Options

// Get JSON response (default)
const jsonResponse = await apiClient.get('/items', {}, {
  headers: {
    'Accept': 'application/json'
  }
})

// Download file as stream
const fileResponse = await apiClient.get('/files/123', {}, {
  responseType: 'stream',
  returnFullResponse: true
})

Error Handling

The API client automatically handles common error cases:

  • 401 responses trigger an ACCESS_TOKEN_EXPIRED error that will attempt to refresh credentials
  • 429 responses trigger a RATE_LIMIT_EXCEEDED error that will retry the request with exponential backoff (only in asynchronous mode, e.g., within a flow run)
  • Other error responses (status >= 300) throw a ConnectionError

Response

By default, the API client:

  1. Returns the response body for successful requests (status 200–299)
  2. Throws an error for failed requests
  3. Handles authentication and rate limiting errors automatically

You can get the full response including status and headers by setting returnFullResponse: true in the options.