# SuiteScript 2.1 RESTlet Skeleton Generator

> Source: https://netray.co/tools/suitescript-restlet-skeleton-generator
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

Fill in a few fields and get a SuiteScript 2.1 RESTlet starter with all four handlers, logging and structured error responses.

## Category

netsuite

## Erp

NetSuite

## Audience

- NetSuite developer
- Integration engineer

## Tool

**Kind:** template

**Output:** code

**Language:** javascript

**Fields:**

#### Script name

**Key:** script_name

**Type:** text

**Default:** Customer Sync RESTlet

#### Author

**Key:** author

**Type:** text

**Default:** Integration team

#### Record type id

**Key:** record_type

**Type:** select

**Options:**

- customer
- vendor
- salesorder
- purchaseorder
- item
- invoice

**Default:** customer

#### First field to return

**Key:** field_a

**Type:** text

**Default:** companyname

#### Second field to return

**Key:** field_b

**Type:** text

**Default:** email

#### Log title prefix

**Key:** log_title

**Type:** text

**Default:** CustSyncRL

**Blocks:**

#### RESTlet script

**Body:** /**
 * @NApiVersion 2.1
 * @NScriptType Restlet
 * @NModuleScope SameAccount
 * @description {{script_name}}
 * @author {{author}}
 */
define(['N/record', 'N/log', 'N/error'], (record, log, error) => {
  const RECORD_TYPE = '{{record_type}}';
  const LOG = '{{log_title}}';

  const fail = (name, message) => {
    throw error.create({ name: name, message: message, notifyOff: true });
  };

  const get = (params) => {
    if (!params || !params.id) {
      fail('MISSING_ID', 'Query parameter id is required');
    }
    const rec = record.load({ type: RECORD_TYPE, id: params.id });
    return {
      id: params.id,
      {{field_a}}: rec.getValue({ fieldId: '{{field_a}}' }),
      {{field_b}}: rec.getValue({ fieldId: '{{field_b}}' })
    };
  };

  const post = (body) => {
    if (!body) {
      fail('MISSING_BODY', 'Request body is required');
    }
    const rec = record.create({ type: RECORD_TYPE, isDynamic: false });
    rec.setValue({ fieldId: '{{field_a}}', value: body.{{field_a}} });
    rec.setValue({ fieldId: '{{field_b}}', value: body.{{field_b}} });
    const newId = rec.save();
    log.audit(LOG, 'Created ' + RECORD_TYPE + ' ' + newId);
    return { id: newId };
  };

  const put = (body) => {
    if (!body || !body.id) {
      fail('MISSING_ID', 'Body must include id');
    }
    const values = {};
    values['{{field_a}}'] = body.{{field_a}};
    values['{{field_b}}'] = body.{{field_b}};
    record.submitFields({ type: RECORD_TYPE, id: body.id, values: values });
    log.audit(LOG, 'Updated ' + RECORD_TYPE + ' ' + body.id);
    return { id: body.id };
  };

  const doDelete = (params) => {
    if (!params || !params.id) {
      fail('MISSING_ID', 'Query parameter id is required');
    }
    record.delete({ type: RECORD_TYPE, id: params.id });
    log.audit(LOG, 'Deleted ' + RECORD_TYPE + ' ' + params.id);
    return { deleted: params.id };
  };

  return { get: get, post: post, put: put, delete: doDelete };
});

#### Calling it

**Body:** GET  https://<accountid>.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=<scriptId>&deploy=<deployId>&id=<internalId>

Use the Authorization header for token-based authentication or OAuth 2.0. Send JSON with Content-Type: application/json for post and put.

**Notes:** Starting point only. Confirm field ids exist on your record, decide whether deletes should be exposed at all, add input validation and consider using a dedicated integration role with least privilege. Deploy to a sandbox first and test each handler.

## Content

**Intro:** A RESTlet is the standard way to expose custom endpoints from NetSuite. This generator produces a SuiteScript 2.1 RESTlet with get, post, put and delete handlers, structured errors and audit logging, so you start from a clean, reviewable file instead of a blank editor.

**Sections:**

#### How to use the generator

**Body:** Enter the script name, the record type id and two fields to return and write. Copy the generated script into a .js file, upload it to the File Cabinet and create a script record of type RESTlet. Deploy it with a role that has only the permissions it needs, then test each handler from a REST client in a sandbox account.

**Bullets:**

- Use lowercase record type ids such as customer or salesorder.
- Check field ids on the record before you test.
- Remove handlers you do not need to shrink the attack surface.

#### Design choices in the template

**Body:** The template loads one record per get, which is fine for single-record reads but expensive in loops. The put handler uses submitFields because it is cheaper than load and save and avoids overwriting unrelated fields. Errors are raised with N/error so callers get a named failure. Logging uses audit level for writes, so you can trace integration activity without flooding the log with debug entries.

#### Limits and cautions

**Body:** A RESTlet has its own governance allowance and a limit on concurrent requests per account, so build clients with retry and backoff. Keep payloads small and paginate list endpoints. Do not return whole records unless the caller needs them, since this exposes fields the integration should not see. For standard record CRUD, the built-in REST record API may be simpler than any custom script.

**Cta:** If you want an integration or agent to read NetSuite safely, Netray can help design a read-only access pattern with role-based permissions and approvals for any write-back.

**Faq:**

#### Should I use a RESTlet or the REST record API?

**Answer:** Use the REST record API for standard record access because it needs no code. Use a RESTlet when you need custom logic, a combined payload or behavior the standard API does not offer.

#### Why does the template use submitFields in put?

**Answer:** submitFields updates only the listed fields and costs fewer governance units than loading and saving a full record. It also runs fewer sourcing and validation steps, so confirm it fits your field rules.

#### How do I authenticate calls to a RESTlet?

**Answer:** Use token-based authentication or OAuth 2.0 with an integration record and a role that can run the script. Each request must carry a valid Authorization header for the account.

#### Can I return an HTTP status code from the script?

**Answer:** A thrown error produces an error response with a status that NetSuite chooses. For fine control over status codes you need to handle errors in the client and return structured error bodies from the script.

## Search terms

suitescript 2.1 restlet example, netsuite restlet template, restlet get post put delete suitescript, netsuite restlet skeleton, suitescript restlet error handling, netsuite restlet record load, restlet NScriptType Restlet

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
