How do you send data to your NetSuite RESTlet using Python?
To send data to your NetSuite RESTlet using Python code utilise the handy
requests_oauthlib
library.
If you need to upload a series of CSV files and want to perform some data cleaning before being uploaded and want to avoid the Import CSV process then you can create a simple RESTlet and insert your clean data directly.
Create Your RESTlet
First, create your RESTlet and make it perform the basic tasks needed to import the data you want.
Keep your RESTlet simple and have it return either errors for improper format, insufficient parameters or IDs of newly created records. Put the emphasis back on the request to have everything you need to create a new record.
I find separating out into distinct modules the scripts that will perform the insertion of data into your records.
A simple RESTlet and the would therefore look something like this:
/**
* @NApiVersion 2.1
* @NScriptType Restlet
*/
define(['N/error'],
/**
* @params {error} error
*/
(error) => {
const doValidation = (props, propNames) => {
const errors = props.reduce(
(accum, prop, idx) => {
if (!prop && prop !== 0) accum.push(`Missing a required argument: ${propNames[idx]}`);
return accum;
}
, []
);
if (errors.length) throw error.create({ name: 'MISSING_REQUIRED_ARGS', message: errors.join("\n") });
}
const post = (params) => {
log.debug({title: 'POST request (params)', details: params});
doValidation([params.haveThis], ['haveThis']);
// check parameters are correct data type, or perform type conversions (if needed)
const haveThis = parseInt(params["haveThis"]) || 0;
// send data through
createMyRecords({haveThis});
}
return {post}
}
);
As you can see from the above code I try to keep the footprint of my RESTlet code light. In essence, I just want to check I have the needed parameter values by using a
doValidation
function similar to what Netsuite have in their documents, but I want to collect ALL errors with the validation process and not just throw at EACH error which the standard docs have.
However, the
very first
thing I tend to write with any RESTlet function (
get
,
post
,
put
,
doDelete
) is the debug log of the parameters coming through. You’ll want to check these values when you first write your Python code when you send your first request. By writing this code first you are diagnosing whether your connection by your external code to the RESTlet passes authentication.
Next, you’ll want to perform all your necessary checks on the
params
object being passed in (the sole argument to the REST function).
After checking the
params
object I will then perform some basic data type conversions if needed. One popular type conversion I do is for dates and I would import the
N/format
library to help with processing these types of variables.
This would look something like this if importing the
N/format
library:
/**
* @NApiVersion 2.1
* @NScriptType Restlet
*/
define(['N/error', 'N/format'],
/**
* @params {error} error
* @params {format} format
*/
(error, format) => {
const doValidation = (props, propNames) => {
const errors = props.reduce(
(accum, prop, idx) => {
if (!prop && prop !== 0) accum.push(`Missing a required argument: ${propNames[idx]}`);
return accum;
}
, []
);
if (errors.length) throw error.create({ name: 'MISSING_REQUIRED_ARGS', message: errors.join("\n") });
}
const post = (params) => {
log.debug({title: 'POST request (params)', details: params});
doValidation([params.haveThis], ['haveThis']);
// check parameters are correct data type, or perform type conversions (if needed)
const haveThis = format.parse({value: parse["haveThis"], type: format.Type.DATE});
// send data through
createMyRecords({haveThis});
}
return {post}
}
);
Once all the checks and types are performed I then send through the data to be processed according to the parameters of the function being passed the information.
I find having my RESTlet code separated from the rest of my code helps to show where problems lie. If you’re having connection issues then the debugging log will not be showing any parameters being received. If you’re having data entry problems then it could be the data being sent through to the processing modules.
Connecting To RESTlet From Python
Once you have uploaded your script to NetSuite and created a RESTlet script record you will need to deploy your script so that you can send your request to an HTTPS endpoint.
Once you’ve created a deployment you will have a URL that looks something like this:
https://{REALM_ID}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script={SCRIPT_ID}&deploy={DEPLOY_ID}
Some components of the URL will be unique to your script and deployment.
Once you have the URL you need to fetch the integration key and secret along with the user access ID and secret. This means you will have 4 hashes in your hand each of which are needed to connect to the endpoint.
The variables
CLIENT_ID
and
CLIENT_SECRET
are the integration key and secrets; whereas the Access Tokens received for the user interacting with the integration are the variables
ACCESS_KEY
and
ACCESS_SECRET
in the code below.
Once you have these five elements you can jump over to your Python code and test you can connect based on these.
Here’s a quick snippet of Python code to run to check:
from requests_oauthlib import OAuth1Session
import json
CLIENT_KEY: str = "HASH"
CLIENT_SECRET: str = "HASH"
ACCESS_KEY: str = "HASH"
ACCESS_SECRET: str = "HASH"
SIGNATURE_METHOD: str = "HMAC-SHA256"
REALM_ID: str = "1234567"
SCRIPT_ID: int = 1
DEPLOY_ID: int = 1
URL: str = f"https://{REALM_ID}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script={SCRIPT_ID}&deploy={DEPLOY_ID}
oauth = OAuth1Session(
client_key=CLIENT_KEY,
client_secret=CLIENT_SECRET,
resource_owner_key=ACCESS_KEY,
resource_owner_secret=ACCESS_SECRET,
realm=REALM_ID
signature_method=SIGNATURE_METHOD
)
data = {"Suite": "Script"}
headers = {
"Content-Type": "application/json"
}
res = oauth.post(URL, data=json.dumps(data), headers=headers)
print(res)owner)
The purpose of this simple Python code is to test your credentials to see you have properly pasted the correct elements into the right variables.
There are a couple of things to be mindful of with this code which can lead to problems if they are taken out.
Firstly, the
signature_method
must be set to
HMAC-SHA256
.
See here for more detail
.
Secondly, a header object needs to be inserted with
"Content-Type": "application/json"
if you want your RESTlet code to handle a JSON object with the data being sent through, otherwise without this header property set the data will be sent through as a string.
Note also that header properties are CASE SENSITIVE
, therefore if you’re sending through
"content-type": "application/json"
it will not be recognised.
If you are getting a
403
error then check you have the correct URL as well as the correct credentials. Double check them again. Don’t write any additional code, you just want to check the connection is good.
Once you get a
200
response you then want to go over to your RESTlet script record and check there has been a debug log of the
data
contained in your Python
data
variable that was passed through.
Summary
Sending data from a Python script to a Netsuite RESTlet is an easy task thanks to the
requests_oauthlib
library which enables users to create a session and making multiple requests to the RESTlet endpoint without having to authenticate at each request submission.