Examples

import type { GithubIssueDemo, NangoSync } from '../../models';

export default async function fetchData(nango: NangoSync) {
    // Fetch issues from GitHub.
    const res = await nango.get({
        endpoint: '/repos/NangoHQ/interactive-demo/issues?labels=demo&sort=created&direction=asc'
    });

    // Map issues to your preferred schema.
    const issues: GithubIssueDemo[] = res.data.map(({ id, title, html_url }: any) => {
        return { id, title, url: html_url };
    });

    // Persist issues to the Nango cache.
    await nango.batchSave(issues, 'GithubIssueDemo');
}

Read more about integration scripts to understand what role they play in Nango.

Integration scripts expose a helper object (NangoSync for sync scripts, NangoAction for action scripts), which allows to interact with external APIs & Nango more easily.

HTTP requests

Makes an HTTP request inside an integration script:

const config = { endpoint: '/some-endpoint' };

await nango.get(config); // GET request
await nango.post(config); // POST request
await nango.put(config); // PUT request
await nango.patch(config); // PATCH request
await nango.delete(config); // DELETE request

Note that all HTTP requests benefit from automatic credential injection. Because scripts are executed in the context of a specific integration & connection, Nango can automatically retrieve & refresh the relevant API credentials.

Parameters

Response

HTTP request retries

To configure retries when HTTP requests fail, use the retries and retryOn parameters in your HTTP requests.

The following will apply:

  • By default, retries are performed for 5xx & 429 statuses, as well as ECONNRESET, ETIMEDOUT, and ECONNABORTED.
  • Use the retryOn parameter to specify an array of additional status codes to retry on.
  • By default, no retries are performed: retries default to 0
  • The retry starting delay is 100ms, the delay between attempts is multiplied by 2 each time (exponential backoff) and there is no maximum delay between retries.

Logging

You can collect logs in integration scripts. This is particularly useful when:

  • developing, to debug your integration scripts
  • in production, to collect information about integration script executions & understand issues

Collect logs in integration scripts as follows:

await nango.log("This is a log.");

Logs can be viewed & searched in the Nango UI. We plan to make them exportable in the future as well.

Environment variables

Integration scripts sometimes need to access sensitive variables that should not be revealed directly in the code.

For this, you can define environment variables in the Nango UI, in the Environment Settings tab. Then you can retrieve these environment variables from integration scripts with:

await nango.getEnvironmentVariables();

Parameters

No parameters.

Response

Trigger action

Integration scripts currently do not support importing files, which limits the ability to share code between integration scripts.

As a temporary workaround, you can call action scripts from other integration scripts with:

await nango.triggerAction('<ACTION-NAME>', { 'custom_key1': 'custom_value1' });

Parameters

Response

Paginate through API responses

Nango provides a helper to automatically paginate endpoint responses.

Similar to HTTP requests, the nango.paginate() method takes in a ProxyConfiguration parameter.

Use the paginate field to of the ProxyConfiguration to specify how the endpoint’s pagination work. Here’s an example for a Jira endpoint:

const config: ProxyConfiguration = {
    // https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-projects/#api-rest-api-3-project-search-get
    endpoint: `/ex/jira/${cloud.cloudId}/rest/api/3/project/search`,
    params: {
        properties: properties
    },
    paginate: {
        type: 'offset',
        offset_name_in_request: 'startAt',
        response_path: 'values',
        limit_name_in_request: 'maxResults',
        limit: 50
    },
    headers: {
        'X-Atlassian-Token': 'no-check'
    },
    retries: 10
};

for await (const projects of nango.paginate<JiraProjectResponse>(config)) {
    const projectsToSave = toProjects(projects, cloud.baseUrl);
    await nango.batchSave(projectsToSave, 'Project');
}

As shown in the example above, use a for loop to iterate through the paginated results.

Nango has pre-configured the pagination settings for some popular APIs, so you don’t have to specify them in scripts.

You can view the pre-configured pagination settings for all APIs in the providers.yaml file.

Please note that some APIs have diverging pagination strategies per endpoint, so you might still need to override pre-configured pagination settings at times.

The pagination helper supports 3 types of pagination: cursor, link or offset with the following settings:

Get Integration

Returns the current integration information

await nango.getIntegration();

With credentials

await nango.getIntegration({ include: ['credentials'] });

Parameters

See GET /integrations/{uniqueKey} query parameters: documentation

Response

See GET /integrations/{uniqueKey} response: documentation

Manage connection metadata

Get connection metadata

Returns the connection’s metadata.

await nango.getMetadata();

Better, you can specify the type of the metadata;

interface CustomMetadata {
    anyKey: Record<string, string>;
}
const myTypedMetadata = await nango.getMetadata<CustomMetadata>();

Parameters

No parameters.

Example Response

Set connection metadata

Set custom metadata for the connection (overrides existing metadata).

await nango.setMetadata({ 'CUSTOM_KEY1': 'CUSTOM_VALUE1' });

Parameters

Response

Empty response.

Edit connection metadata

Edit custom metadata for the connection. Only overrides & adds specified properties, not the entire metadata.

await nango.updateMetadata({ 'CUSTOM_KEY1': 'CUSTOM_VALUE1' });

Parameters

Response

Empty response.

Get the connection credentials

Returns a specific connection with credentials.

await nango.getConnection();

The response content depends on the API authentication type (OAuth 2, OAuth 1, API key, Basic auth, etc.).

When you fetch the connection with this API endpoint, Nango will check if the access token has expired. If it has, it will refresh it.

We recommend not caching tokens for longer than 5 minutes to ensure they are fresh.

Parameters

Example Response

Sync-specific helper methods

Sync scripts persist data updates to the Nango cache, which your app later fetches (cf. step-by-step guide).

Save records

Upserts records to the Nango cache (i.e. create new records, update existing ones). Each record needs to contain a unique id field used to dedupe records.

const githubIssues: GitHubIssue[] = ...; // Fetch issues from GitHub API.

await nango.batchSave(githubIssues, 'GitHubIssue');

Parameters

Delete records

Marks records as deleted in the Nango cache. Deleted records are still returned when you fetch them, but they are marked as deleted in the record’s metadata (i.e. soft delete).

The only field that needs to be present in each record when calling batchDelete is the unique id; the other fields are ignored.

const githubIssuesToDelete: { id: string }[] = ...; // Fetch issues to delete from GitHub API.

await nango.batchDelete(githubIssuesToDelete, 'GitHubIssue');

Parameters

Update records

Updates records in the Nango cache by merging the given data into the existing record. The id field is required in each record and used to determine what existing record to merge into.

batchUpdate is primarily useful in webhook sync scripts, where you receive partial updates from a webhook and want to merge them into the existing records.

The merge algorithm used is a deep merge. Nested objects are merged recursively, while arrays always use the new value for the array. Any fields not present in the update record are left unchanged.

// Create partial GitHub Issue update records with only id and state.
const githubIssues: Pick<GitHubIssue, "id" | "state">[] = ...; 

await nango.batchUpdate(githubIssues, 'GitHubIssue');

Take special care when using batchUpdate with records containing arrays. The merge algorithm does not attempt to merge arrays, but rather always uses the value of the new array.

// given a an existing record: 
// { id: '1', tags: [{id: 12, name: 'Dev'}, {id: 13, name: "QA"}] }
const updates: Pick<Issue, "id" | "tags">[] = [
    { id: '1', tags: [{id: 14, name: 'UX'}] }
];

// after the update, the record will be: 
// { id: '1', tags: [{id: 14, name: "UX"}] }
await nango.batchUpdate(updates, 'Issue');

Parameters

Get records

Fetches records from the Nango cache by ID. Returns a Map where the keys are the requested IDs, and the values are the corresponding records. Any records that are not found will simply be absent from the map.

Example usage:

const records = await nango.getRecordsById<string, Issue>(['1', '2', '3'], 'Issue');

if (records.has('1')) {
    const record = records.get('1');
    await nango.log(record.title);
} else {
    await nango.log('Record with id 1 not found.');
}

Fetching records by ID is useful when you need to update specific records with a more granular approach than nango.batchUpdate(), which performs a deep merge. Note that nango.batchUpdate() is more performant than using nango.getRecordsById(), followed by nango.batchSave().

A common use case is when handling external webhooks, where only a partial update of a record is received from an API.

Action-specific helper methods

ActionError

You can use ActionError in an action script to return a descriptive error to your app when needed:


export default async function runAction(nango: NangoAction): Promise<Response> {
    // Something went wrong...

    throw new ActionError({ any_key: 'any_value' });
}

In this case, the response to the trigger action call will be:

{
  "error_type": "action_script_failure",
  "payload": {
    "any_key": "any_value"
  }
}

Relative imports in scripts

You can import relative files into your scripts to allow for code abstraction and to maintain DRY (Don’t Repeat Yourself) principles. This means you can reuse code across different scripts by importing it. The imported file must live in the nango-integrations directory and can be imported in the following way:

import type { GithubIssueDemo, NangoSync } from '../../models';
import { issueMapper } from '../mappers/issue-mappper';

export default async function fetchData(nango: NangoSync) {
    // Fetch issues from GitHub.
    const res = await nango.get({
        endpoint: '/repos/NangoHQ/interactive-demo/issues?labels=demo&sort=created&direction=asc'
    });

    // Persist issues to the Nango cache.
    await nango.batchSave(issueMapper(res.data), 'GithubIssueDemo');
}

Note that you cannot import third-party modules at this time. Additionally, if there is a compilation error in an imported file, the entry point file will also fail to compile.

Pre-included Dependencies

Some libraries are pre-included for usage in scripts:

Please reach out in the community if you would like to request additional ones.

Questions, problems, feedback? Please reach out in the Slack community.