How to use a google script web app with Node.js - node.js

I deployed a web app using google apps script and when I try to make requests to it using Node.js I get the following error:
Google Drive Page Not Found - Sorry, unable to open the file at this time
But everything works fine when I'm sending the requests using Postman.
This is my node.js code:
const options = {
'method': 'post',
'gzip': true,
'accept': '*/*',
'content-length': 0,
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
'url': 'https://script.google.com/macros/s/script-id/exec'
}
request(options, (error, response, body) => {
if(response.statusCode == 200) {
res.sendStatus(200);
}
else {
res.sendStatus(500);
}
});
This is the content of the google apps script web app:
function doPost(e) {
return ContentService.createTextOutput(JSON.stringify({success: true}));
}
There are a couple more questions related to this topic, but the solution they provide is to remove /u/# from the URL ... which does not apply in my case.
Could this happen because I'm making requests from a http server to a web app deployed on https? That's the only thing that I'm thinking of...
Update:
I've also tried to send the request from a HTTPS node server and it still doesn't work.
Making a GET request works fine.

Making POST requests from a Node.js server to a web app deployed using Google Apps Script requires the 'Content-Length' header to be specified, and also the followAllRedirects option set to true, which is needed because the initial request is a redirect to another request that returns the response.
The working code looks like this:
const options = {
'method': 'post',
'gzip': true,
'body': [],
'followAllRedirects': true,
'headers': {
'Content-Length': 0 // length of the specified `body`
},
'url': 'https://script.google.com/macros/s/scriptID/exec'
}
request(options, (error, response, body) => {
if(response.statusCode == 200) {
res.sendStatus(200);
}
else {
res.sendStatus(500);
}
});
Hopefully this will help others that are facing this issue.

When publishing the web app inside Google Apps Script, make sure you have set the "Who has access" option to "Anyone, including anonymous".
Also, it may not work if your organization does not allow sharing of Drive files outside the organization. This setting can only be changed by the GSuite admin.

Related

node.js how to send multipart form data in post request

I am attempting to get data in the form of an image sent from elsewhere using multipartform, however when trying to understand this via the great sanctuary(stack overflow) there are missing elements I don't quite understand.
const options = {
method: "POST",
url: "https://api.LINK.com/file",
port: 443,
headers: {
"Authorization": "Basic " + auth,
"Content-Type": "multipart/form-data"
},
formData : {
"image" : fs.createReadStream("./images/scr1.png")
}
};
request(options, function (err, res, body) {
if(err) console.log(err);
console.log(body);
});
2 questions:
what is the variable auth, what do I initialize it to/where/how do I declare it
what is the url "api.LINK.com", is this just the site url where this code is on
After your comments I think I may be doing this wrong. The goal is to send data(an image) from somewhere else(like another website) to this node app, then the nodeapp uses the image and sends something back.
So that I would be the one creating the API endpoint

Node.js service: Getting "Cannot GET /<path>" after POST request in microservice (works locally)

I've created a node.js microservice using the libraries express and request.
The idea is to forward a post-request by the client application from the first endpoint ("http://example.com/proxy/x") to the second one ("http://example.com/x"). If I do the request to /proxy/x via POSTMAN locally to my "localhost:/proxy/x" instance, it works just fine. The request gets the expected response without any problem. If I push it to the cloud environment using a containering system and ask the endpoint via "http://example.com/proxy/x" it says "CANNOT /GET /x" and fails with a 404 error.
To cover the "404" error, I've even created a app.get listener on "/proxy/x".
Now it returns "error = true". That means my POST is turned to a GET call.
The url is already hardcoded, before I've generated it with a combination of req.protocol and req.get('host'). Seems to generate a valid url, still does not work.
POST http://example.com/proxy/target
app.post('/proxy/target', (req, res) => {
// const currentURL = req.protocol + '://' + req.get('host');
const requestBody = req.body;
request.post({
url: 'http://example.com/target',
followAllRedirects: true, // I've also tried to outcomment it
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic user:password',
},
form: requestBody
},
(err, response, body) => {
if (err) {
return console.log(err);
} else {
// console.dir(response);
return res.status(response.statusCode).send(response.body);
}
}
);
});
app.route('/target')
.post(function (req, res) {
//some code
});
Expected result should be the response body the call delivers, if I'm callign /target directly.
{
'success':true
}
It actually is responding with:
Cannot GET /x/
As it works perfectly on my localhost, it might be the case that my cloud dev environment is the problem.
I would be glad for additional ideas. The cloudsystem is a containering environment called CloudFoundry.
Update:
It seems like CloudFoundry is using NGINX per default: https://docs.cloudfoundry.org/buildpacks/nginx/index.html
Other developers had similar issues when using NGINX: https://www.digitalocean.com/community/questions/post-request-redirects-to-get-in-nginx-proxy-and-nodejs

NTLM Api access with Node.js

Full disclaimer: I have never worked with Microsofts NTLM before.
I've tried around 30 different ways to access the 7Pace timetracker API on our local TFS instance. I know it works if i access the URI directly in Chrome, it prompts me for my AD login, and swiftly serves me all the data requested. Same for Postman, except there is an authentication tab for NTLM ahead of time.
Postman suggests this for Node.js using request:
var request = require("request");
var options = {
method: 'GET',
url: 'http://TFSURL/odata/TimeExport%28StartDate=%272018-11-14%27,EndDate=%272018-11-14%27%20,PopulateTopParentColumns=null,GroupTimeByDateByUser=null,IncludeBillable=null%29',
headers: {
'cache-control': 'no-cache',
Authorization: 'NTLM NOTTHEREALTOKENKJASDKLHWKLLASBEDBSDAOBAW'
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
This returns nothing. Notice the Authorization header. I've tested multiple different variants of similar. My next guess was to request through Chrome, then sniff it with Tellerik Fiddler and try to replicate the headers. I've done this as well, but to no avail. I end up with a very similar result to that above, except chrome uses negotiate:
Any ideas on how to go about this ? Maybe other debugging options?
You will need to through the 3 steps of authentication for NTLM. It's not that easy if you want to do it manually as the NTLM spec is not really open.
There's Node.js module you can use: https://www.npmjs.com/package/httpntlm (disclaimer: I created it)
To GET your url, you would need the following:
var httpntlm = require('httpntlm');
httpntlm.get({
url: "http://tfs2:8090/api/FlexPOS%20APS/odata/TimeExport%28StartDate=%272018-11-14%27,EndDate=%272018-11-14%27%20,PopulateTopParentColumns=null,GroupTimeByDateByUser=null,IncludeBillable=null%29",
username: 'your username',
password: 'your password',
workstation: 'anything',
domain: ''
}, function (err, res){
if(err) return err;
console.log(res.headers);
console.log(res.body);
});

Accessing private repositories in organizations on Github Enterprise via REST

Problem: Need to download a private repository that is within an organization hosted on GitHub Enterprise.
I created a personal access token for my account with scope repo and stored it as an environment variable, GITHUB_ACCESS_TOKEN.
I'm using NodeJS with the request library to make the GET request. However, with the following code, I get a 401 response when I run it.
(Note: I replaced <repo-name> with the actual name of the repository).
Can someone explain why this doesn't work and point me in the right direction?
My Function :
function downloadRepository(owner, repository, branch, accessToken) {
let options = {
method: "GET",
url: `https://api.github.com/orgs/${owner.toLowerCase()}/repos/${repository.toLowerCase()}/tarball/${branch}?access_token=${accessToken}`,
headers: {
'Accept': 'application/vnd.github.v3.raw',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'
}
};
request(options, (error, response, body) => {
if(error || response.statusCode != 200) {
console.log("Could not download repository: %s", response.statusCode);
return;
}
return body;
});
}
My Main :
const request = require('request');
let wiki = downloadRepository("deep-learning-platform", "<repo-name>", "wiki",
process.env.GITHUB_ACCESS_TOKEN);

api call fails with request module in node.js app

The following API call fails for me when I try it in my app. It works fine from same machine in the browser. I should get a JSON response.
var url = 'http://www.btc38.com/trade/getTradeList.php?coinname=BTC';
request.get({ url: url, json: json, strictSSL: false, headers: { 'User-Agent' : '' } }, function (err, resp, data) {
});
edit: by "fails" i mean i get a non-json error page.
You can't use an empty User-Agent header, otherwise the request fails.
So use something like:
'User-Agent' : 'request/x.y'

Resources