@neatsuite/http
v2.1.3
Published
A TypeScript-first NetSuite API client with built-in OAuth 1.0a authentication, retry logic, and performance monitoring
Maintainers
Readme
@neatsuite/http
A TypeScript-first NetSuite API client with built-in OAuth 1.0a authentication, automatic retries, performance monitoring, and excellent developer experience. Lightweight and using only 3 dependencies.
Features
- 🔐 OAuth 1.0a Authentication - Built-in support for NetSuite's OAuth requirements
- 🔄 Automatic Retries - Configurable retry logic with exponential backoff
- 📊 Performance Monitoring - Track API call durations and performance metrics
- 🎯 TypeScript First - Full type safety and IntelliSense support
- 🚀 Optimized - Connection pooling, compression, and efficient error handling
- 🛠️ Developer Friendly - Clean API, detailed errors, and extensive utilities
- 📦 Zero Config - Works out of the box with sensible defaults
- 🔌 Extensible - Middleware support for custom logic
Installation
npm install @neatsuite/http
# or
yarn add @neatsuite/http
# or
pnpm add @neatsuite/httpQuick Start
import { NetSuiteClient } from '@neatsuite/http';
// Initialize the client
const client = new NetSuiteClient({
oauth: {
consumerKey: 'your-consumer-key',
consumerSecret: 'your-consumer-secret',
tokenKey: 'your-token-key',
tokenSecret: 'your-token-secret',
realm: 'your-realm'
},
accountId: 'your-account-id'
});
// Make a RESTlet call
const response = await client.restlet({
script: '123',
deploy: '1',
params: { action: 'getCustomer', id: '456' }
});
console.log(response.data);Configuration
const client = new NetSuiteClient({
oauth: {
consumerKey: process.env.NETSUITE_CONSUMER_KEY!,
consumerSecret: process.env.NETSUITE_CONSUMER_SECRET!,
tokenKey: process.env.NETSUITE_TOKEN_KEY!,
tokenSecret: process.env.NETSUITE_TOKEN_SECRET!,
realm: process.env.NETSUITE_REALM!
},
accountId: process.env.NETSUITE_ACCOUNT_ID!,
// Optional configuration
timeout: 30000, // Request timeout in ms (default: 15000)
retries: 5, // Number of retry attempts (default: 3)
enablePerformanceLogging: true, // Log performance metrics (default: false)
headers: { // Custom headers for all requests
'User-Agent': 'MyApp/1.0'
}
});API Methods
RESTlet Calls
// GET request to a RESTlet
const response = await client.restlet({
script: '123',
deploy: '1',
params: {
action: 'search',
type: 'customer',
query: 'Acme Corp'
}
});
// POST request to a RESTlet
const response = await client.restlet(
{
script: '456',
deploy: '2'
},
{
method: 'POST',
body: {
action: 'create',
record: {
name: 'New Customer',
email: '[email protected]'
}
}
}
);Direct API Calls
// GET request
const response = await client.get('https://api.netsuite.com/v1/records/customer/123');
// POST request
const response = await client.post(
'https://api.netsuite.com/v1/records/customer',
{
name: 'New Customer',
email: '[email protected]'
}
);
// PUT request
const response = await client.put(
'https://api.netsuite.com/v1/records/customer/123',
{ email: '[email protected]' }
);
// DELETE request
const response = await client.delete('https://api.netsuite.com/v1/records/customer/123');Generic Request Method
const response = await client.request({
url: 'https://api.netsuite.com/v1/records/customer',
method: 'POST',
body: { name: 'New Customer' },
headers: { 'X-Custom-Header': 'value' },
retries: 5 // Override default retries for this request
});Error Handling
import { NetSuiteClient, NetSuiteError } from '@neatsuite/http';
try {
const response = await client.get('/api/v1/records/customer/999999');
} catch (error) {
if (NetSuiteClient.isNetSuiteError(error)) {
console.error('NetSuite Error:', error.message);
console.error('Status:', error.status);
console.error('Code:', error.code);
console.error('Details:', error.details);
} else {
console.error('Unexpected error:', error);
}
}Middleware
Add custom logic to all requests:
// Add authentication token to all requests
client.use(async (context, next) => {
context.config.headers = {
...context.config.headers,
'X-Auth-Token': await getAuthToken()
};
return next();
});
// Log all requests
client.use(async (context, next) => {
console.log(`Making request to ${context.config.url}`);
const response = await next();
console.log(`Response status: ${response.status}`);
return response;
});Utilities
Response Caching
import { ResponseCache, createCacheKey } from '@neatsuite/http';
const cache = new ResponseCache();
// Cache a response
const key = createCacheKey(url, 'GET', params);
cache.set(key, responseData, 300); // Cache for 5 minutes
// Get cached response
const cached = cache.get(key);
if (cached) {
return cached;
}Rate Limiting
import { RateLimiter } from '@neatsuite/http';
const limiter = new RateLimiter(100, 60000); // 100 requests per minute
if (limiter.canMakeRequest()) {
limiter.recordRequest();
const response = await client.get(url);
} else {
const waitTime = limiter.getTimeUntilNextRequest();
console.log(`Rate limited. Wait ${waitTime}ms`);
}Request Batching
import { RequestBatcher } from '@neatsuite/http';
const batcher = new RequestBatcher(async (ids) => {
const response = await client.post('/api/batch', { ids });
return new Map(response.data.map(item => [item.id, item]));
});
// These requests will be batched together
const [user1, user2, user3] = await Promise.all([
batcher.add('123'),
batcher.add('456'),
batcher.add('789')
]);Date Utilities
import { formatNetSuiteDate, parseNetSuiteDate } from '@neatsuite/http';
// Format date for NetSuite
const nsDate = formatNetSuiteDate(new Date()); // "2024-01-15"
// Parse date from NetSuite
const date = parseNetSuiteDate("2024-01-15"); // Date objectQuery Building
import { buildSearchQuery } from '@neatsuite/http';
const query = buildSearchQuery({
type: 'customer',
status: 'active',
created: ['2024-01-01', '2024-01-31'],
tags: ['vip', 'premium']
});
// "type = 'customer' AND status = 'active' AND created IN ('2024-01-01','2024-01-31') AND tags IN ('vip','premium')"Custom Logger
import { Logger } from '@neatsuite/http';
const customLogger: Logger = {
debug: (message, meta) => console.debug(`[DEBUG] ${message}`, meta),
info: (message, meta) => console.info(`[INFO] ${message}`, meta),
warn: (message, meta) => console.warn(`[WARN] ${message}`, meta),
error: (message, meta) => console.error(`[ERROR] ${message}`, meta)
};
const client = new NetSuiteClient(config, customLogger);Best Practices
Environment Variables: Store OAuth credentials securely
const client = new NetSuiteClient({ oauth: { consumerKey: process.env.NETSUITE_CONSUMER_KEY!, consumerSecret: process.env.NETSUITE_CONSUMER_SECRET!, tokenKey: process.env.NETSUITE_TOKEN_KEY!, tokenSecret: process.env.NETSUITE_TOKEN_SECRET!, realm: process.env.NETSUITE_REALM! }, accountId: process.env.NETSUITE_ACCOUNT_ID! });Error Handling: Always wrap API calls in try-catch blocks
try { const response = await client.get(url); return response.data; } catch (error) { if (NetSuiteClient.isNetSuiteError(error) && error.status === 404) { return null; // Handle not found } throw error; // Re-throw other errors }Rate Limiting: Implement rate limiting for high-volume operations
const limiter = new RateLimiter(10, 1000); // 10 requests per second for (const id of largeIdList) { while (!limiter.canMakeRequest()) { await new Promise(resolve => setTimeout(resolve, 100)); } limiter.recordRequest(); await client.get(`/api/v1/records/customer/${id}`); }Caching: Cache frequently accessed, rarely changing data
const cache = new ResponseCache(); async function getCustomer(id: string) { const cacheKey = `customer:${id}`; const cached = cache.get(cacheKey); if (cached) return cached; const response = await client.get(`/api/v1/records/customer/${id}`); cache.set(cacheKey, response.data, 3600); // Cache for 1 hour return response.data; }
Module Formats
This package provides optimized builds for Node.js environments:
- ES Modules (ESM):
import { NetSuiteClient } from '@neatsuite/http' - CommonJS (CJS):
const { NetSuiteClient } = require('@neatsuite/http')
Browser/UMD Usage
For browser, AMD/RequireJS, and UMD environments, use the separate UMD package:
npm install @neatsuite/http-umdThe UMD package includes all dependencies bundled and provides:
- Browser global support (
neatHttp) - AMD/RequireJS compatibility
- Minified production builds
- CDN support
See @neatsuite/http-umd for browser usage examples.
TypeScript Support
This package is written in TypeScript and provides comprehensive type definitions:
import type {
NetSuiteConfig,
NetSuiteResponse,
NetSuiteError,
NetSuiteRequestOptions
} from '@neatsuite/http';
// Type-safe configuration
const config: NetSuiteConfig = {
oauth: {
consumerKey: '...',
consumerSecret: '...',
tokenKey: '...',
tokenSecret: '...',
realm: '...'
},
accountId: '...'
};
// Type-safe responses
const response: NetSuiteResponse<Customer> = await client.get<Customer>('/api/v1/customer/123');
const customer: Customer = response.data;License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues and feature requests, please use the GitHub issue tracker.
