Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

nsrestlet

MichaelEPope6.1kMIT2.0.1

A module to help you create and use connections to your Netsuite Restlets.

netsuite, restlet, oauth, token, based, authentication, tba, ns, nlauth

readme

NSRestlet

A module which makes connecting to NetSuite RESTlets using OAuth and NLAuth much easier.

npm package

Known Vulnerabilities Build Status Coverage Status HitCount

npm install nsrestlet

Why NSRestlet?

Connecting to NetSuite RESTlets with external programs can be really hard.

  • NLAuth has to deal with password changes and two factor authentication problems (which are required on high-permission accounts)
  • OAuth is really hard to set up
  • NetSuite errors for debugging NLAuth and OAuth applications are somewhat vague
  • The examples they have on SuiteAnswers don't always seem to work

Usage

var nsrestlet = require('nsrestlet');

//For OAuth (we can do NLAuth too, see later in documentation):
var accountSettings = {
    accountId: "PUT YOUR ACCOUNT ID HERE",
    tokenKey: "PUT YOUR TOKEN KEY HERE",
    tokenSecret: "PUT YOUR TOKEN SECRET HERE",
    consumerKey: "PUT YOUR CONSUMER KEY HERE",
    consumerSecret: "PUT YOUR CONSUMER SECRET HERE" };
var urlSettings = {
    url: 'https://ACCOUNTID.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=SCRIPTID&deploy=DEPLOYID'
 }

//create a link
var myInvoices = nsrestlet.createLink(accountSettings, urlSettings)

//then call get, post, put, or delete
myInvoices.get({id: '12345'}, function(error, body)
{
    console.log(body);
});

That may look a bit intimidating, but trust me, it's not. Here is a tutorial on how to set up OAuth with Netsuite, which makes things much easier, even if you aren't familiar with OAuth.

Getting Started

Authorization

First, ensure that you have set up your Netsuite environment for OAuth or NLAuth and created your script

In order to create a connection to Netsuite, you need to provide some account settings.

For OAuth, the account settings will look like this:

//all fields are required
var accountSettings = {
    accountId: "PUT YOUR ACCOUNT ID HERE",
    tokenKey: "PUT YOUR TOKEN KEY HERE",
    tokenSecret: "PUT YOUR TOKEN SECRET HERE",
    consumerKey: "PUT YOUR CONSUMER KEY HERE",
    consumerSecret: "PUT YOUR CONSUMER SECRET HERE"
}; 

For NLAuth, the account settings look like this:

//all fields except role are required
var accountSettings = {
    accountId: "PUT YOUR ACCOUNT ID HERE",
    email: "PUT YOUR EMAIL HERE",
    password: "PUT YOUR PASSWORD HERE",
    role: "PUT YOUR ROLE KEY HERE"     //optional, but recommended
};

URL Settings

You also need to provide some URL settings. The URL settings can be formatted in one of two ways.

Use an explicit URL. This is listed on the script deployment page in Netsuite as the EXTERNAL URL field:

var urlSettings = {
    url: "https://12345.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=1&deploy=1"
};

External URL field

Alternatively, provide the script id and deployment id (either the string version or number version). These can be found on the script and script deployment pages in Netsuite in the ID field:

// You can use the string version...
var urlSettings = {
    script: "customscript_test_restlet",
    deployment: "customdeploy_test_restlet"
}

// or, the number version
var urlSettings = {
    script: 142,
    deployment: 1
}

Script ID field

Deployment ID field

Once you've created the account settings and url settings objects, pass them into nsrestlet.createLink():

var invoiceLink = nsrestlet.createLink(accountSettings, urlSettings);

This link allows you to call a restlet endpoint in an easy, clean, and repeatable way. It also allows you to reuse the account settings to connect to other restlets.

Calling the Endpoint

Once you have a link, you can directly call the four basic HTTP methods (GET, POST, PUT, DELETE).

The first parameter you provide is the data which will be sent to the restlet.

The second parameter is an optional callback. If not provided, a promise will be returned instead. This callback or promise will receive data from your NetSuite Restlet.

For GET requests, make sure the data you provide is strings or a one-level-deep JS object with strings. For PUT, POST, and DELETE, you can use any JS object you'd like.

// Using callbacks
invoiceLink.get({tranid: 12345}, function(error, body) {
    console.log(error, body);
});

// Promises
invoiceLink.post({tranid: 12345}).then(function(body) {
    console.log(body);
})
.catch(function(error) {
    console.log(error);
});

// invoiceLink also has .put() and .delete() methods

Note that for GET requests, you should limit the data you post to 1 level deep strings.

Receiving and Returning Data in the Restlet

Inside of your Restlet script in NetSuite, you will receive the data as the first parameter:

function restlet_called(body)
{
  // you receive the payload as 'body'

  // if your application likes JSON, you can send data back to it like this:
  return {message: "I got your message", data: body}

  // ...otherwise send it as a string using JSON.stringify()
}

Or in SuiteScript 2.0:

/**
 * @NApiVersion 2.x
 * @NScriptType Restlet
 */

define(['N/log'], 
    function(log) 
    {
        function restlet_called(body) 
        {
            // you receive the payload as 'body'

            // if your application likes JSON, you can send data back to it like this:
            return {message: "I got your message", data: body}

            // ...otherwise send it as a string using JSON.stringify()
        }
        return {
            get:    restlet_called,
            post:   restlet_called,
            put:    restlet_called,
            delete: restlet_called
        };
});

For GET, POST, and PUT requests, you can return data back to the external application.

This data will be provided in the callback or promise (depending on which you are using).

// for example as a callback
invoiceLink.post({tranid:12345}, function(error, body) {
    console.log(body);
    /*
        You'd see this printed out:

        { message: "I got your message",
          data: { tranid:12345 } }
    */
});

For DELETE requests, you won't receive any data back, but you should still provide a callback or promise resolution to catch any errors that might occur.

Error Handling and Retries

Sometimes things go wrong when trying to call a Restlet, and an error is emitted.

In cases like rate limiting or dropped requests, nsrestlet will retry the call (by default up to three times) before emitting an error. In other cases where retrying wouldn't make a difference, nsrestlet will emit an error immediately.

You can receive this error in you callback (error parameter) or promise (.catch()).

You can customize the retry settings by adding some fields to the URLSettings object.

var urlSettings = {
    script: 142,
    deployment: 1,
    retries: 5,     // number of retries on retryable errors, default is 3
    backoff: 120    // multiplicative backoff in ms, default is 0
}  

Backoff refers to how many milliseconds to delay on a retryable error if a request fails. The backoff is multiplicative, so each failure (in this case, 3 of them), will double the time delay (120, 240, 480 milliseconds). This is a useful field if you're receiving rate limiting errors from NetSuite.

Need more Customization?

Here is some basic code you can start with. It provides a good base for a custom solution.

Want to help with Development?

Feel free. Please see the Development page to get started.

License

MIT (see LICENSE file). But we love contributions and suggestions. Please feel free to suggest improvements.

Credits

This module was made after looking at a lot of good code. Here is some the code that inspired this module and effected how it was designed:

  • bknight's response in this thread is excellent - the idea of a facade for four HTTP codes works really well. The error handling and retrying capabilities also comes from looking at his code. He was generous enough to post a full example of what was working on his end.
  • suiteplus has an excellent module called nscabinet, which helps upload and download files from Netsuite as a gulp task. Reading through it helped me understand how to use the querystring module and NLAuth.
  • Marty Zigman has a good sample that got me pointed in the right direction.
  • These excellent modules are used in this project - request, oauth-1.0a, and qs.

This package has also been helped by:

  • Some conversations with scottvonduhn and battk on the Unofficial Netsuite Slack Server. If you have Netsuite related questions, this is the place to go.
  • Some excellent pull requests by awesome folk here on Github.

Version Changes

Please see the Changelog

changelog

Change Log for nsrestlet

2.0.1

Updated a broken link in the readme. No code changes.

2.0.0

Updated the oauth-1.0a module from version 1.0.1 to version 2.2.5.

This required a breaking change, as crypto is no longer built in to oauth-1.0a and is instead supplied by Node.JS (which is better for security). In rare situations, Node.JS may be built without crypto, causing the module not to work. In these situations, I'll suggest to people that they use the earlier versions (I don't want to be the judge on whether a 3rd party cryptography module is secure).

Fixed a bug in the backoff.

There was a bug in the backoff that might have prevented the backoff from being implemented appropriately. It's now fixed.

Removed the contentType option from URL Settings

It turns out that Netsuite doesn't care too much about what contentType you request. It all depends on what you return in the restlet. If you return an object, it returns straight JSON, if you return a string, it will return text. I'm not sure if this is new behavior or if it's always been this way and I just didn't realize it. It will throw an error if you ask for text/html and you return a JS object, but besides that, it doesn't make a difference at all. So contentType option is useless, and might as well be removed

Can now return JSON with GET

Originally, the module always returned a request from GET as a string, regardless of whether it was returned in the restlet as a JS object or a string. This is because Netsuite always sent it back as a string. The new version of the module will now return strings as strings and JSON as JSON. I felt this was more consistent and so it'd be a good change. DELETE doesn't return anything, as per usual.

Coverage and Testing

This is a bit of a work in progress. I'm trying to integrate the module into Travis-CI and Coveralls. That will help it appear a bit higher in the npm search, and also give you guys a bit more confidence about the testing. I found a few bugs in implementing it, so it seems to work great!

Added a Webpage

This is expected for npm packages, so I just did something simple. I'll make it more nice looking later. It feels rather unnecessary though.

Added a Development file

I wanted to make it easier for other people to contribute to the library, if they wanted to. There's a lot of steps, this file helps streamline them so they can get it going pretty easily.

1.0.1

Updated the Readme.

Just spelling changes. No code changes.

1.0.0

The Initial Commit.

Upcoming Changes (haven't happened yet)

Considering moving off of the request() module

See this. While it might be completely fine, I'm a bit worried that they are letting contributors automatically commit. That could be easily abused if it gets in the wrong hands. I'll either wait a bit and see if it remains safe, or change to a similar module in the future.

Cleaning Up The Documentation

While the documentation is very detailed, it's also a bit of a mess. Honestly, I'd like it to be 'so simple you can't get it wrong'. This means I need to add pictures, and organize it so it's really easy to get set up. Maybe a YouTube video?