Expand your SuiteScript skills in the Sustainable SuiteScript community for NetSuite developers.

SuiteScript Short - Reduce Repetition when Working with Records

Created: March 5, 2024

A pretty common complaint I hear about the SuiteScript API is that it's too verbose. It often takes a lot of repetitive typing to accomplish common tasks. I've seen some teams go so far as to build their own abstraction layer over the top of the SuiteScript API just to make it more palatable for themselves.

I completely agree that SuiteScript can be verbose, but I promise we don't need to do anything so elaborate or complex or fraught as re-writing SuiteScript in its entirety.

Rather, we can arrange our data in a data structure more conducive to iteration, then take advantage of native JavaScript iteration methods and syntactic sugar to focus our code on the characters that really matter.

Setting a bunch of fields on a record?

The N/record API is notoriously verbose.

Turn this:

const customer = record.create({ type: record.Type.CUSTOMER })
  .setFieldValue({
    fieldId: 'subsidiary',
    value: customerModule.getSubsidiary(customerData)
  })
  .setFieldValue({
    fieldId: 'companyname',
    value: customerModule.generateName(customerData)
  })
  .setFieldValue({
    fieldId: 'email',
    value: customerData.email
  })
  .setFieldValue({
    fieldId: 'url',
    value: customerData.website
  })
  .setFieldValue({
    fieldId: 'phone',
    value: customerData.phone
  })

const customerId = customer.save()

into this:

const customer = record.create({ type: record.Type.CUSTOMER });

[
  // [fieldId, fieldValue]
  ['subsidiary', customerModule.getSubsidiary(customerData)],
  ['companyname', customerModule.generateName(customerData)],
  ['email', customerData.email],
  ['url', customerData.website],
  ['phone', customerData.phone]
].forEach(([fieldId, value]) => {
  customer.setValue({ fieldId, value })
})

const customerId = customer.save()

The latter has ~20% fewer characters (not counting line breaks) - 428 compared to the former's 536. The savings increase linearly as you add more fields.

You add new field values by adding a new [fieldId, fieldValue] pairing to the Array, and that's it.

Retrieving data from a sublist?

Sublists are a particularly egregious offender.

Turn this:

const lineCount = salesOrder.getLineCount({ sublistId: 'item' })
const items = []

for (let i = 0; i < lineCount; i++) {
  items.push({
    id: salesOrder.getSublistValue({
      sublistId: 'item',
      fieldId: 'item',
      line: i
    }),
    amount: salesOrder.getSublistValue({
      sublistId: 'item',
      fieldId: 'amount',
      line: i
    }),
    rate: salesOrder.getSublistValue({
      sublistId: 'item',
      fieldId: 'rate',
      line: i
    }),
    total: salesOrder.getSublistValue({
      sublistId: 'item',
      fieldId: 'total',
      line: i
    })
  })
}

into this:

const itemFields = ['item', 'amount', 'rate', 'total']
const itemCount = salesOrder.getLineCount({ sublistId: 'item' })
const items = [...Array(itemCount)]
  .map((_, line) => {
    const currentLine = { sublistId: 'item', line }
    return itemFields.reduce((itemData, fieldId) => {
      itemData[fieldId] = salesOrder.getSublistValue({
        ...currentLine,
        fieldId
      })
      return itemData
    }, {})
  })

The latter has ~29% fewer characters (not counting line breaks) - 413 compared to the former's 582. Again the savings increase linearly as you add more fields.

You add more fields to the result by adding new field IDs to itemFields, and that's it.

Data First, Boilerplate Later

It's certainly nice that they require less typing, but what I like about them the most is that they put the data you care about - the fields and values you're setting or reading - right at the front, all in one spot. You don't have to hunt through method call after repeated method call to figure out which columns you're pulling or where the value for the email field comes from.

If you're the type that likes to abstract SuiteScript like I mentioned above, you could for instance take the map() call above and encapsulate it in a readSublist method and shorten things even further. I prefer to shy away from this myself so that my students and the folks who inherit my code don't have to learn two separate APIs.

If you haven't been using SuiteScript 2.1, my approach probably looks wildly unfamiliar. I'm taking advantage of many modern JavaScript features here, which are available to you when you use SuiteScript 2.1:

If you're not already familiar with these JavaScript features, or you're not using SuiteScript 2.1, I can't recommend strongly enough that you start practicing reading and writing with these tools. They'll allow you to write code that brings the important stuff forward and pushes the boilerplate to the background.

SuiteScript 2.1

Are you taking advantage of the power of SuiteScript 2.1? Have an approach you like better?

Join the Sustainable SuiteScript community and share your thoughts.