Netsuite SuiteScript RESTlet get URL information - netsuite

Using this example RESTlet code below, is there any way to get information about the HTTP request's calling URL? I know my deployment URL is this (shown below), but how can I get that information in my get, delete, post, or put functions?
https://123123-abc.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1
I call the above URL in Postman or other client apps and I pass in header info and a JSON payload. I only have access to the JSON payload inside my RESTlet code below. I would like to get access to the URL that was called.
/**
*#NApiVersion 2.x
*#NScriptType Restlet
*/
define(['N/record', 'N/error'],
function(record, error) {
// Get a standard NetSuite record
function _get(context) {
// Is there a way to get information about the request URL at this point?
return JSON.stringify(record.load({
type: context.recordtype,
id: context.id
}));
}
return {
get: _get,
delete: _delete, // not shown
post: post, // not shown
put: put, // not shown
};
});

I am answering my own question. This is one way I found to get the URL navigation paths within Netsuite. Using the N/url module provided by Netsuite, I can do the following. If there are better ways, let me know.
require(['N/url'], function(url) {
var host = url.resolveDomain({
hostType: url.HostType.APPLICATION
});
console.log(host)
// result = 123123-abc.app.netsuite.com
})

Related

how can I get an element in a redirect url using node.js

Non-English country, please forgive my spelling mistakes.
For example, I want to first redirect url1(http://localhost:3000/api/song/167278) to url2(http://localhost:4000/api/song/167278) to use url2's api. And url2 will reponse a json file, which can be seen in the postman's panel.
(postman's pannel)
But there maybe a lot of elements, I only want an element in the file, such as data[0].url. How can I return just return the url value (data[0].url in this json) when people access http://localhost:3000/api/song/167278.
I am using express.js now, how can I edit it? Or is there any other methods?
app.get('api/song/:id', async (req, res) => {
try {
const { id } = req.params
url = "http://localhost:4000/api/song/" + id
res.redirect(url)
}
catch (e) {
console.log(e)
}
}
You could either proxy the entire request there or fetch localhost:4000/api/song/1 in your request handler (with something like node-fetch or axios or with node's APIs and send the fields that you want back to the client as json.

Netsuite - Getting error: Fail to evaluate script: All SuiteScript API Modules are unavailable while executing your define callback

I have the below script that I am trying to upload but am getting a Fail to evaluate script: All SuiteScript API Modules are unavailable while executing your define callback - error.
Not sure what I am doing wrong as I am basically following the example in the api.
Note: This is being done in Sandbox.
/**
* #NApiVersion 2.x
* #NScriptType Suitelet
* #NModuleScope SameAccount
*/
define(['N/email'],
/**
* #param {email} email
*/
function(email){
function sendEmail() {
var senderId = 34972;
var recipientEmail = 'email#example.com';
email.send({
author: senderId,
recipients: recipientEmail,
subject: 'Test Sample Email Module',
body: 'Thisis a test',
});
}
sendEmail();
});
If you are writing a Suitelet script in 2.0, you need to use the RETURN of your callback function. In your case, it will look something like the following:
return {
onRequest : sendEmail
};
May I also ask - is there any reason why you are trying to trigger an email send via a SUITELET? Assuming you want to trigger the email via the URL generated on the "script deployment" page of the Suitelet, you should consider including the ServerResponse call to write on your browser that the email was sent successfully. That will look something like the following:
context.response.write('Email now sent');
Lastly - I also see that you have wrongfully used a comma at the end of your 'email.send' object. Remove the comma as pointed out below:
email.send({
author: senderId,
recipients: recipientEmail,
subject: 'Test Sample Email Module',
body: 'Thisis a test', <---- REMOVE COMMA!
});
Hope this helps.
That is not a correct suitelet and you are calling your function inside the define.
The functions returned from the define() may call Netsuite functions but your sendemail function is calling Netsuite APIs “inside” the define.
If you are just trying to wrap your head around SuiteScript change your define to a require and call that code in a console window.
Otherwise review the suitelet docs and return the correct function object.
Here's a straight forward answer... comment out anything that isn't native suite script code... your custom modules, classes and Upload. then edit it in the file cabinet and and un comment your stuff

Netsuite-Suitelet post to restlet get parameters

I am executing a restlet by a post request in a suitelet. The restlet runs fine and I am able to pass data back from restlet--->suitelet, but I am unable to pass data from the suitelet to the restlet when I call the restlet.
suitelet
var test = 'test';
var parameters = {'custscripttest_input':test};
var apiURL='https://3864948-
sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl?
script=xxx&deploy=1';
try{
var restletResponse=https.post({
url:apiURL,
headers:header,
body:postData,
params:parameters
});
restlet
var testInput =
runtime.getCurrentScript().getParameter({name:'custscripttest_input'});
No parameters show in runtime.getCurrentScript. I have created the parameter in the restlet script record.
I have also tried passing body data and retrieving in the restlet like so:
var data = context.request.parameters
I seemed to have overlooked my body:postData format. My post data body structure in my suitelet was
var postData={input:{"cust_input": test}
I retrieved data in the restlet using context.input.cust_input;
The params in an http(s) request are added to the url. They are not passed through to the script deployment parameters of the restlet.
Restlets don't give access to query string parameters when a body is included.
If you need the parameters you could format your postbody as:
body:JSON.stringify({
params:parameters,
body:postData // have postData still as an object at this point.
})

SailsJS : Redirecting to controller action with variables

I am using sailsJS with ejs engine and i want to redirect the user back to the input page with messages ( validation errors ... ) .
i used to use this easily with laravel in PHP ( return redirect('dashboard')->with('status', 'Profile updated!'); )
i.e : i need to redirect the user back saying that this site dont exist
find : function(req,res){
var id = req.param(íd');
Site.find(id).where({isDeleted : null })
.exec(function(err,siteFound){
if(err) console.log(err);
if(siteFound) {
return res.view('site/show', {
site : siteFound
});
} else {
return res.redirect('/site');
}
})
},
i searched in sails documentation but found nothing. how can this be performed in SailsJS ?
thanks
UPDATE : i found what i needed exactly by installing sails-hook-flash . the feature i needed is called flash messages.
Thank you for your help !
Blockquote
I can't quite tell if you want a true browser redirect. A browser redirect means sending a message back to the browser that says "use this other url instead", and then it gets fresh data (meaning new req and res objects) from your app. If this is what you want, I'd say the only real options for passing data are query strings, like:
return res.redirect('/site?message=notfound');
Then in your recieving controller action for site you can access this via req.param('message').
However, if you just want to return the appropriate content now without getting the browser to redirect, you can just call whatever view or controller action you like:
if(siteFound) {
return res.view('site/show', {
site : siteFound
});
} else {
// uncomment one of the options:
// ONE: return another view
// return res.view('site/notfound, {requested: id});
// TWO: pass to another controller action in same controller
// req.options.message = 'not found';
// return module.exports.someOtherAction(req, res);
// THREE: pass to a controller action in another controller
// req.options.message = 'not found';
// var OtherController = require('./OtherController');
// return OtherController.someOtherAction(req, res);
}
Any of those three options will keep you at the user's requested url ("/site/abc123" or whatever), but display the content you specify.
res.notfound("my message string"); should do it right?
You can work with res.json() if it is an ajax request expecting a custom response.
Read the docs about the res object HERE and the custom notfound response HERE.

How to include access-token in the HTTP header when requesting a new page from browser

The similar question was asked by someone else (here) but got no proper answer. Since this is basic and important for me (and maybe for someone else as well), I'm trying to ask here. I'm using Node.js+Express+EJS on the server side. I struggled to make the token authentication succeeded by using jsonwebtoken at the server and jQuery's ajax-jsonp at the web browser. Now after the token is granted and stored in the sessionStorage at the browser side, I can initiate another ajax request with the token included in the request header, to get the user's profile and display it somewhere in the 'current' page. But what I want is to display a new web page to show the user's profile instead of showing it in the 'current' page (the main/index page of the website). The question is:
How to initiate such an HTTP GET request, including the token in the HTTP header; and display the response as a new web page?
How the Node.js handle this? if I use res.render then where to put the js logic to verify the token and access the DB and generate the page contents?
Or, should we say the token mechanism is more suitable for API authentication than for normal web page authentication (where the web browser provides limited API)?
I think the answer to this question is important if we want to use the token mechanism as a general authentication since in the website scenario the contents are mostly organized as web pages at the server and the APIs at the client are provided by the browser.
By pure guess, there might be an alternative way, which the ajax success callback to create a new page from the current page with the response from the server, but I have no idea of how to realize that as well.
By calling bellow code successfully returned the HTML contents in customer_profile.ejs, but the client side ajax (obviously) rejected it.
exports.customer_profile = function (req, res) {
var token = req.headers.token;
var public_key = fs.readFileSync(path.resolve() + '/cert/public_key.pem');
var decoded = jwt.verify(token, public_key);
var sql = 'SELECT * FROM customer WHERE username = "' + decoded.sub + '"';
util.conn.query(sql, function (err, rows) {
if (!err) {
for (var i = 0; i < rows.length; i++) {
res.render('customer_profile', {customer_profile: rows[i]});
break;
}
}
});
};
I am trying to find a solution to this as well. Please note, I am using Firebase for some functionality, but I will try to document the logic as best as I can.
So far what I was able to figure out is the following:
Attach a custom header to the HTTP request client-side
// landing.js - main page script snippet
function loadPage(path) {
// Get current user's ID Token
firebase.auth().currentUser.getIdToken()
.then(token => {
// Make a fetch request to 'path'
return fetch(`${window.location.origin}/${document.documentElement.lang}/${path}`, {
method: 'GET',
headers: {'X-Firebase-ID-Token': token} // Adds unverified token to a custom header
});
})
.then(response => {
// As noted below, this part I haven't solved yet.
// TODO: Open response as new webpage instead of displaying as data in existing one
return response.text();
})
.then(text => {
console.log(text);
})
.catch(error => {
console.log(error);
});
}
Verify the token according to your logic by retrieving the corresponding header value server-side
// app.js - main Express application server-side file
// First of all, I set up middleware on my application (and all other setup).
// getLocale - language negotiation.
// getContext - auth token verification if it is available and appends it to Request object for convenience
app.use('/:lang([a-z]{2})?', middleware.getLocale, middleware.getContext, routes);
// Receives all requests on optional 2 character route, runs middleware then passes to router "routes"
// middleware/index.js - list of all custom middleware functions (only getContext shown for clarity)
getContext: function(req, res, next) {
const idToken = req.header('X-Firebase-ID-Token'); // Retrieves token from header
if(!idToken) {
return next(); // Passes to next middleware if no token, terminates further execution
}
admin.auth().verifyIdToken(idToken, true) // If token provided, verify authenticity (Firebase is kind enough to do it for you)
.then(token => {
req.decoded_token = token; // Append token to Request object for convenience in further middleware
return next(); // Pass on further
})
.catch(error => {
console.log('Request not authorized', 401, error)
return next(); // Log error to server console, pass to next middleware (not interested in failing the request here as app can still work without token)
});
}
Render and send back the data
// routes/index.js - main router for my application mounted on top of /:lang([a-z]{2})? - therefore routes are now relative to it
// here is the logic for displaying or not displaying the page to the user
router.get('/console', middleware.getTranslation('console'), (req, res) => {
if(req.decoded_token) { // if token was verified successfully and is appended to req
res.render('console', responseObject); // render the console.ejs with responseObject as the data source (assume for now that it contains desired DB data)
} else {
res.status(401).send('Not authorized'); // else send 401 to user
}
});
As you can see I was able to modularize the code and make it neat and clear bu use of custom middleware. It is right now a working API returning data from the server with the use of authentication and restricted access
What I have not solved yet:
As mentioned above, the solution uses fetch API and result of the request is data from server (html) and not a new page (i.e when following an anchor link). Meaning the only way with this code now is to use DOM manipulation and setting response as innerHTML to the page. MDN suggests that you can set 'Location' header which would display a new URL in the browser (the one you desire to indicate). This means that you practically achieved what both, you and I wanted, but I still can't wrap my head around how to show it the same way browser does when you follow a link if you know what I mean.
Anyways, please let me know what you think of this and whether or not you were able to solve it from the part that I haven't yet

Resources