Enhancing SuiteScript with Third-Party Libraries: TypeScript, Zod, and Webpack

April 29, 2024 | 5 minute read
Mohammed Kassem
SuiteCloud Advocate
Text Size 100%:

Welcome back to my walkthrough of third-party library integration in SuiteScript 2.1. In this guide, I’ll demonstrate how to integrate the Zod library, a TypeScript-first schema declaration library, into your SuiteCloud project for runtime data validation. Zod is a powerful library that ensures data accuracy within your SuiteCloud projects.

Here's what you'll learn:

  • Why data validation is invaluable for RESTlets.
  • Zod's magic: effortless runtime validation.
  • How to leverage TypeScript for improved code quality.
  • Step-by-step instructions to integrate Zod, TypeScript, and Webpack.

By the end, you'll be a data validation master building reliable and performing efficient SuiteCloud Projects with confidence.

The complete source code can be found here.

Type Definitions and Data Validation

TypeScript's static typing system is used in SuiteScript to catch errors early and enhance code maintainability. However, as TypeScript is transpiled into JavaScript, type validation is checked at compile time, and this leaves a large hole in our type safety. Zod fills that gap with its runtime validation with type safety by enforcing data structure conformity at runtime and supports code completion, which streamlines development by allowing developers to write more accurate code quickly.

At a high level, here’s why runtime validation is important:

  • Immediate error detection: Captures input errors on the fly before data is processed or stored.
  • Data integrity: Ensures that all data conforms to defined schemas, maintaining the consistency of the data throughout the application.
  • Improved reliability: Reduces the risk of application crashes or unexpected behavior due to invalid data.

There are other runtime validation libraries out there, but here’s why Zod stands out:

  • Zero dependencies: Zod is self-contained, simplifying deployment and compatibility.
  • Environment agnostic: Fully operational in Node.js environments and all modern browsers, aligning with SuiteScript's flexible nature.
  • Lightweight footprint: At just 8 KB when minified and gzipped, Zod is an efficient choice for client and server-side scripts.

By implementing TypeScript definitions in SuiteCloud and utilizing Zod for schema creation, data structure and validation are managed effectively, enhancing RESTlets and user event scripts. This dual approach secures data integrity and minimizes the likelihood of runtime errors.

Implementing Zod for Data Validation in RESTlets

Follow these steps to validate data in RESTlets using Zod:

  1. Install Zod and NetSuite types via npm.
  2. Configure TypeScript to resolve NetSuite types and output compiled scripts to the correct SuiteScripts directory.
  3. Set up Webpack to handle external libraries like Zod as AMD modules.

The integration also involves configuring the amdConfig.json and webpack.config.js files to ensure that Zod is correctly bundled and available within the SuiteScript environment. The RESTlet script can then utilize Zod to validate incoming data against predefined schemas, enhancing the robustness and reliability of data transactions within NetSuite.

  1. Let's start by adding the following libraries to package.json:

{
   "devDependencies": {

       "@hitc/netsuite-types": "^2023.1.9",
       "typescript": "^5.0.4",
       "webpack": "^5.88.2",
       "webpack-cli": "^5.1.4"
   },
   "dependencies": {
       "zod": "^3.22.2"
   }
}

Note: These packages update versions over time. Use  npm install <package_name> to install the latest version.

  1. In the terminal, run npm install in the root directory to install the build time and runtime libraries.

Note: NetSuite types is a compile-time (devDependency) library while Zod is a runtime library.

  1. Modify the TypeScript config file tsconfig.json in the root directory:

"compilerOptions": {
     "paths": {
     "N": ["node_modules/@hitc/netsuite-types/N"],
     "N/*": ["node_modules/@hitc/netsuite-types/N/*"]
   },

   "outDir": "src/FileCabinet/SuiteScripts/"
},

...
}

  1. In the restlet.ts file, add the @NAmdConfig annotation and point to the amdConfig.json:

/**
   *
@NApiVersion 2.1

   * @NScriptType Restlet
   * @NAmdConfig /SuiteScripts/amdConfig.json
*/

  1. Modify webpack.config.js to include NetSuite-types and zod libraries as follows:

module.exports = {
...
externals: [/^N\//, /^N$/, 'zod'],
externalsType: 'amd',
...
};

  1. Set up the amdConfig.json file with the key “zod” and the value pointing to the zod library. In this case, I’ve created a folder in File Cabinet called libs/zod and added Zod’s UMD library.

{
   "paths": {

       "zod": "./libs/zod/index.umd.js"
   }
}

Note: We only do this for Zod because it’s a runtime library, so we can ignore doing this for NetSuite types. The amdConfig.json should be placed in the root directory in the File Cabinet.

  1. In the restlet.ts file in the TypeScript folder, add the following code:

/**
   * @NApiVersion 2.1
   * @NScriptType Restlet
   * @NAmdConfig /SuiteScripts/amdConfig.json
*/
import {type EntryPoints} from "N/types"
import log from 'N/log'
import search from 'N/search'
import record from 'N/record'
import z from 'zod'
const CompanyModel = z.object({
   companyName: z
       .string({required_error: 'Company name is required'})
       .min(5, 'Company name shoudl be at least 5 characters long'),
   email: z
       .string({required_error: 'Email is required'})
       .email('Email should be an email address')
})
type
CompanyModel = z.infer<typeof CompanyModel>
export
const post: EntryPoints.RESTlet.post = (dataIn) => {
   log.debug(
'post', dataIn);
   const company = CompanyModel.parse(dataIn)
   const customer = record.create({type: 'customer'});
   customer.setValue(
'subsidiary', '1');
   customer.setValue(
'companyname', company.companyName);
   customer.setValue(
'email', company.email)
   const customerId = customer.save()
   log.audit(
'post', `Created customer ${customerId}`);
   return {customerId};
}


This TypeScript code for a NetSuite RESTlet uses the Zod library to define a data validation schema for a company object. The line type CompanyModel = z.infer<typeof CompanyModel> generates a TypeScript type based on the Zod schema, which enables type-checking and annotations within the TypeScript code for improved reliability and development experience.

When the RESTlet receives data, the .parse method is invoked on this schema to validate the incoming data against the defined rules. If the data meets the schema's constraints, the method processes it further to create a new customer record in NetSuite. If the data fails validation, Zod throws an error, preventing invalid data from being processed and ensuring data integrity within the application.

Conclusion

In this journey of integrating Zod for data validation in SuiteScript, we've seen firsthand the power of third-party libraries in enhancing the functionality of our SuiteCloud projects. The practical steps and insights provided here should empower you as a developer to confidently incorporate Zod or similar libraries into your SuiteScript projects. Remember, effective integration goes beyond implementation; it involves understanding the small details of the development environment and making informed decisions about library compatibility and application performance. As always, the SuiteScript community remains an invaluable resource for collaboration and learning, helping us navigate the complexities of third-party library integration and push the boundaries of what we can achieve in NetSuite's versatile platform.

Mohammed Kassem

SuiteCloud Advocate


Previous Post

Integrating Third-Party Libraries in SuiteScript 2.1: A Detailed Guide

Mohammed Kassem | 6 min read

Next Post


Research Checklist: SuiteScript Compatibility with Third-Party Libraries

Mohammed Kassem | 6 min read