parse2 upgrade javascript promise question - javascript

I have the following old parse2 code that I need to upgrade to parse4. I have the following snippet of original code: EDIT: realized it was using old request (requestLib). I have replaced that with axios and now am showing my changes::
var query = new Parse.Query(request.params.documentType);
query.equalTo('objectId', request.params.documentObjectId);
return query.first({ useMasterKey: true })
.then(function (result) {
if (!result) { return Promise.error('Sorry, this document is not available to be sent.'); }
documentObject = result;
return result
})
.then(function(result){
if (useNewHTMLEmail) {
if (p.type === undefined) {
return console.log("type property must be defined for HTML template")
}
return Parse.Cloud.run("getEmail", {documentId: request.params.documentObjectId, type: p.type, text: baseMessage, documentType: p.documentType, customFields: p.customFields })
.then(function(result) {
baseMessage = result;
return true;
})
}
else {
return Promise.resolve();
}
})
.then(function (result) {
if (p.appendPDF == true && documentObject.get('pdf') !== undefined) {
var download = function (uri, filename, callback) {
requestLib.head(uri, function (err, res, body) {
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
requestLib(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
var url = documentObject.get('pdf').url();
var parts = url.split("/");
var lastSegment = parts.pop() || parts.pop();
var promise = new Parse.Promise();
download(url, lastSegment, function () {
file = fs.readFileSync(lastSegment);
promise.resolve(result);
});
return promise;
}
else {
return Promise.resolve(result);
}
})
So far I have made the following changes:
var query = new Parse.Query(request.params.documentType);
query.equalTo('objectId', request.params.documentObjectId);
documentObject = await query.first({ useMasterKey: true });
if (documentObject === undefined){
throw new Error("Bad document in sendMail");
}
if (useNewHTMLEmail) {
if (p.type === undefined) {
throw new Error("type property must be defined for HTML template")
}
baseMessage = await Parse.Cloud.run("getEmail", {documentId: request.params.documentObjectId, type: p.type, text: baseMessage, documentType: p.documentType, customFields: p.customFields })
}
The next section is where I get confused using callbacks and async await. Here is my attempt with Axios:
var url = documentObject.get('pdf').url();
var parts = url.split("/");
var lastSegment = parts.pop() || parts.pop();
axios({
method: 'get',
url: url,
responseType:'stream'
})
.then(res => {
res.data.pipe(fs.createWriteStream(lastSegment));
})
.catch(err => console.log(err));
How do I translate this portion now:
var promise = new Parse.Promise();
download(url, lastSegment, function () {
file = fs.readFileSync(lastSegment);
promise.resolve(result);
});
EDIT: Why doesn't this pass through:
var writeStream = fs.createWriteStream(lastSegment);
await new Promise(async (resolve) => {
const response = await axios({
method: "GET",
url: url,
responseType: "stream"
});
response.data.pipe(writeStream);
writeStream.on('error', function (err) {
console.log(err);
});
});
file = fs.readFileSync(lastSegment); <=== never gets executed.
Thanks

What do I replace Promise.resolve() with?
Nothing. The return Promise.resolve() does nothing in a then callback, in fact it could have been omitted even there.
Or, the "return promise"?
You'll need to construct and await a new Promise for the download. But you'd probably want to modernise that function as well, getting rid of the readFileSync and altogether replacing requestLib with something that returns a promise instead of a stream.

This worked:
var writeStream = fs.createWriteStream(lastSegment);
console.log("start axios");
const response = await axios({
method: "GET",
url: url,
responseType: "stream"
});
response.data.pipe(writeStream);
writeStream.on('error', function (err) {
console.log(err);
});
file = fs.readFileSync(lastSegment);

Related

Getting returned value from another javascript file using async

class monitor {
constructor(){
this.delay = config.delay
delay(time) {
return new Promise(function (resolve) {
setTimeout(resolve, time);
});
}
async redacted (pid) {
if (this.err === true) {
await this.delay(this.delay)
}
console.log("MONITOR > Getting Item Attrs")
const options = {
method: 'get',
url: url + pid + '.json',
headers: {
accept: '*/*',
'accept-encoding': 'gzip, deflate, br',
},
proxy: this.proxy
}
return req(options)
.then((res) => {
//console.log(res)
let variants = res.data.skus
//console.log(variants)
const att = []
for (let [key, value] of Object.entries(variants)) {
if(value.inStock) att.push(key)
}
if(att.length >= 1){
console("MONITOR > Sourced Item")
return att;
} else {
("MONITOR > No Variants Available")
this.oos = true
this.redacted(config.pid);
}
})
.catch((err) => {
if (err?.response?.status == 403) {
console.error("MONITOR > Proxy Block # GET PRODUCT")
this.err = true
this.redacted(config.pid);
}
})
}
}
var hello = new monitor().redacted(config.pid);
console.log(hello)
From what I understand I need to wait for the promise to finish before returning but I am confused on how to execute this with my code and also call this file and store the return value in another file. I'm not sure if my formatting is wrong as well, but I tried changing and no fix anyways
This snippet isn't using asynch but, it gives you the idea. You need to await or .then the promise (the fetch/request). You first fetch the remote JSON file then you parse it / read it. Something like:
function getJSON(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
//xhr.responseType = 'json';
xhr.onload = function () {
var status = xhr.status;
if (status == 200) {
resolve(JSON.parse(xhr.response)); // <---------------
} else {
reject(status);
}
};
xhr.send();
});
};
getJSON(primaryURL).then(function (res) {
if (res) {
//do something
} else {
console.log("response not found");
}
}).catch(function (error) {
console.log("Error getting document:", error);
});

how to resolve 'NodeJS API call response is an un-parsable object'?

I am getting the below result after my API call.
My node version is 12.x
{"type":"Buffer","data":[123,34,101,114,114,111,114,115,34,58,91,34,74,87,84,32,105,115,32,101,120,112,105,114,101,100,32,111,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,112,114,111,112,101,114,32,39,101,120,112,39,32,99,108,97,105,109,34,93,125,11]}
Please see the code snippet below:
let postOptions = {
host: 'vault.server',
path: '/v1/auth/gcp/login',
method: HTTPS.POST_REQUEST,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Vault-Namespace': 'mynamespace'
},
json: true,
rpDefaults: {
strictSSL: false
}
};
let requestPayLoad = {
"role": this._vaultRole,
"jwt": signedJWT
};
console.log(JSON.stringify(requestPayLoad));
console.log(JSON.stringify(postOptions));
try {
let result = await HTTPS.makeRequest(postOptions, JSON.stringify(requestPayLoad), HTTPS.POST_REQUEST);
console.log('Response***************',JSON.stringify(result));
return result.auth.client_token;
}
Please see the below code snippet for the http make request method.
return new Promise((resolve, reject) => {
let rq = https.request(options, (res) => {
let response;
let chunks = [];
res.on('data', (chunk) => {
chunks.push(chunk);
});
res.on('end', () => {
response = Buffer.concat(chunks);
return resolve(response);
});
});
rq.on('error', (e) => {
return reject({'statusCode': 500, 'success': false, 'error': e.toString()});
});
if (type === 'POST') {
rq.write(data);
}
rq.end();
});
Please help me to resolve this
You are receiving the data as a Buffer. Use the toString() method to convert this buffer into a string inside the try block.
try {
let result = await HTTPS.makeRequest(postOptions, JSON.stringify(requestPayLoad), HTTPS.POST_REQUEST);
console.log('Response***************', result.toString());
return result.auth.client_token;
}
If you want to access the data from the response returned from you API call
do:
let data = result.data;
and I you want to get client_token as showing here:
return result.auth.client_token;
it's not possible because the response does not have auth attribute on it:
{"type":"Buffer","data":[123,34,101,114,114,111,114,115,34,58,91,34,74,87,84,32,105,115,32,101,120,112,105,114,101,100,32,111,114,32,100,111,101,115,32,110,111,116,32,104,97,118,101,32,112,114,111,112,101,114,32,39,101,120,112,39,32,99,108,97,105,109,34,93,125,11]}

JS Functions to make an API call

I have the following code.
I'm trying to make an API call (retrieve) passing since (obj.since), therefore, every time I make the call the API does not retrieve all data. However, so far, I haven't found the way to get since from the last record on my database.
var express = require("express");
var article = require("../models/article");
var request = require('request');
article.findOne({}, {since:1, _id:0}, { sort: { 'since' : -1 } }, function (err,obj) {
var **dataString** = `'{"consumer_key":"XXXXX", "access_token":"XXXXXXX", "since":"${obj.since}"}'`;
});
var options = {
url: 'https://xxxxxxxxx.com/v3/get',
method: 'POST',
headers: headers,
body: **dataString**
}
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
let package = JSON.parse(body);
for(var attributename in package.list){
var title = package.list[attributename]["given_title"] ;
var url = package.list[attributename]["given_url"] ;
var newArticle = {title: title, url: url, since: since}
article.create(newArticle, function(error, newlyCreated){
if(error){
console.log(error);
} else {
console.log(newlyCreated);
}
});
}
}
else {
console.log(error);
}
};;
request(options,callback)
How can I make an API call getting the obj.since from the database (MongoDB) and pass it to an object (options)?
You are doing async callback style operation in for loop which is causing this issue. I will change few things
Change findOne to have exec at the end so it returns promise
article.create already returns a promise if no callback specified.
Convert request to a promise style.
Use for..of loop to do async operation.
The code will look like this
var express = require("express");
var article = require("../models/article");
var request = require('request');
function hitApi(dataString) {
return new Promise((resolve, reject) => {
var options = {
url: 'https://xxxxxxxxx.com/v3/get',
method: 'POST',
headers: headers,
body: dataString
}
request(options, error, response, body => {
if (err) {
reject(err);
}
resolve(body);
});
});
}
async function perform() {
const dataString = await article.findOne({}, {since:1, _id:0}, { sort: { 'since' : -1 } }).exec();
const response = await hitApi(dataString);
const package = JSON.parse(response.body);
for (const attributename of package.list) {
var title = package.list[attributename]["given_title"] ;
var url = package.list[attributename]["given_url"] ;
var newArticle = {title: title, url: url, since: since}
const newlyCreated = await article.create(newArticle);
console.log(newlyCreated);
}
}
You can then call perform function. There might be few syntax error but you will get an idea.

Amazon S3 Remote File Upload with Axios

I am trying to write a function that would:
Take a remote URL as a parameter,
Get the file using axios
Upload the stream to amazon s3
And finally, return the uploaded url
I found help here on stackoverflow. So far, I have this:
/*
* Method to pipe the stream
*/
const uploadFromStream = (file_name, content_type) => {
const pass = new stream.PassThrough();
const obj_key = generateObjKey(file_name);
const params = { Bucket: config.bucket, ACL: config.acl, Key: obj_key, ContentType: content_type, Body: pass };
s3.upload(params, function(err, data) {
if(!err){
return data.Location;
} else {
console.log(err, data);
}
});
return pass;
}
/*
* Method to upload remote file to s3
*/
const uploadRemoteFileToS3 = async (remoteAddr) => {
axios({
method: 'get',
url: remoteAddr,
responseType: 'stream'
}).then( (response) => {
if(response.status===200){
const file_name = remoteAddr.substring(remoteAddr.lastIndexOf('/')+1);
const content_type = response.headers['content-type'];
response.data.pipe(uploadFromStream(file_name, content_type));
}
});
}
But uploadRemoteFileToS3 does not return anything (because it's a asynchronous function). How can I get the uploaded url?
UPDATE
I have further improved upon the code and wrote a class. Here is what I have now:
const config = require('../config.json');
const stream = require('stream');
const axios = require('axios');
const AWS = require('aws-sdk');
class S3RemoteUploader {
constructor(remoteAddr){
this.remoteAddr = remoteAddr;
this.stream = stream;
this.axios = axios;
this.config = config;
this.AWS = AWS;
this.AWS.config.update({
accessKeyId: this.config.api_key,
secretAccessKey: this.config.api_secret
});
this.spacesEndpoint = new this.AWS.Endpoint(this.config.endpoint);
this.s3 = new this.AWS.S3({endpoint: this.spacesEndpoint});
this.file_name = this.remoteAddr.substring(this.remoteAddr.lastIndexOf('/')+1);
this.obj_key = this.config.subfolder+'/'+this.file_name;
this.content_type = 'application/octet-stream';
this.uploadStream();
}
uploadStream(){
const pass = new this.stream.PassThrough();
this.promise = this.s3.upload({
Bucket: this.config.bucket,
Key: this.obj_key,
ACL: this.config.acl,
Body: pass,
ContentType: this.content_type
}).promise();
return pass;
}
initiateAxiosCall() {
axios({
method: 'get',
url: this.remoteAddr,
responseType: 'stream'
}).then( (response) => {
if(response.status===200){
this.content_type = response.headers['content-type'];
response.data.pipe(this.uploadStream());
}
});
}
dispatch() {
this.initiateAxiosCall();
}
async finish(){
//console.log(this.promise); /* return Promise { Pending } */
return this.promise.then( (r) => {
console.log(r.Location);
return r.Location;
}).catch( (e)=>{
console.log(e);
});
}
run() {
this.dispatch();
this.finish();
}
}
But still have no clue how to catch the result when the promise is resolved. So far, I tried these:
testUpload = new S3RemoteUploader('https://avatars2.githubusercontent.com/u/41177');
testUpload.run();
//console.log(testUpload.promise); /* Returns Promise { Pending } */
testUpload.promise.then(r => console.log); // does nothing
But none of the above works. I have a feeling I am missing something very subtle. Any clue, anyone?
After an upload you can call the getsignedurl function in s3 sdk to get the url where you can also specify the expiry of the url as well. You need to pass the key for that function. Now travelling will update with example later.
To generate a simple pre-signed URL that allows any user to view the
contents of a private object in a bucket you own, you can use the
following call to getSignedUrl():
var s3 = new AWS.S3();
var params = {Bucket: 'myBucket', Key: 'myKey'};
s3.getSignedUrl('getObject', params, function (err, url) {
console.log("The URL is", url);
});
Official documentation link
http://docs.amazonaws.cn/en_us/AWSJavaScriptSDK/guide/node-examples.html
Code must be something like this
function uploadFileToS3AndGenerateUrl(cb) {
const pass = new stream.PassThrough();//I have generated streams from file. Using this since this is what you have used. Must be a valid one.
var params = {
Bucket: "your-bucket", // required
Key: key , // required
Body: pass,
ContentType: 'your content type',
};
s3.upload(params, function(s3Err, data) {
if (s3Err) {
cb(s3Err)
}
console.log(`File uploaded successfully at ${data.Location}`)
const params = {
Bucket: 'your-bucket',
Key: data.key,
Expires: 180
};
s3.getSignedUrl('getObject', params, (urlErr, urlData) => {
if (urlErr) {
console.log('There was an error getting your files: ' + urlErr);
cb(urlErr);
} else {
console.log(`url: ${urlData}`);
cb(null, urlData);
}
})
})
}
Please check i have update your code might its help you.
/*
* Method to upload remote file to s3
*/
const uploadRemoteFileToS3 = async (remoteAddr) => {
const response = await axios({
method: 'get',
url: remoteAddr,
responseType: 'stream'
})
if(response.status===200){
const file_name = remoteAddr.substring(remoteAddr.lastIndexOf('/')+1);
const content_type = response.headers['content-type'];
response.data.pipe(uploadFromStream(file_name, content_type));
}
return new Promise((resolve, reject) => {
response.data.on('end', (response) => {
console.log(response)
resolve(response)
})
response.data.on('error', () => {
console.log(response);
reject(response)
})
})
};
*
* Method to pipe the stream
*/
const uploadFromStream = (file_name, content_type) => {
return new Promise((resolve, reject) => {
const pass = new stream.PassThrough();
const obj_key = generateObjKey(file_name);
const params = { Bucket: config.bucket, ACL: config.acl, Key: obj_key, ContentType: content_type, Body: pass };
s3.upload(params, function(err, data) {
if(!err){
console.log(data)
return resolve(data.Location);
} else {
console.log(err)
return reject(err);
}
});
});
}
//call uploadRemoteFileToS3
uploadRemoteFileToS3(remoteAddr)
.then((finalResponse) => {
console.log(finalResponse)
})
.catch((err) => {
console.log(err);
});

Return Promise From REST Call

I'm trying to invoke a REST call and return a promise so I can manipulate the data afterwhich.
var self = this;
var returnPromise;
returnPromise = self.httpService.testService();
returnPromise.then(function(result){
console.log(result);
});
My REST service is located in another file which has the following:
testService() {
console.log("start of testService");
var request = require('request');
var user = "test";
var ipadd = "127.0.0.1";
request({
url: 'https://' + 'LocalHost' + '/URLOFWEBSERVICE',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
userID: user,
userIpAddress: ipadd
}
}, function(error, response, body) {
if (error) {
console.log(error);
} else {
console.log(response.statusCode, body);
var newPro = new Promise(function(fulfill, reject) {
fulfill(body);
});
console.log(newPro);
return newPro;
}
});
}
I'm able to print out response.stateCode , body( REST result) and the "invoked fulfill" console is printed out.
The problem lies with the
returnPromise.then
in the first page, in which ".then" returns me undefined.
At first I thought that it might be the promise has been called before the REST returns me a response. So, I thought of doing a timeout function to test.
setTimeout(
function(){
console.log(returnPromise);
}
, 5000);
But even so, returnPromise returns me "undefined".
If you expect a function to return a promise, it should return a promise
your testService does not return anything
this does:
testService() {
console.log("start of testService");
var request = require('request');
var user = "test";
var ipadd = "127.0.0.1";
return new Promise(function(fulfill, reject) {
request({
url: 'https://' + 'LocalHost' + '/URLOFWEBSERVICE',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
userID: user,
userIpAddress: ipadd
}
}, function(error, response, body) {
if (error) {
// reject the promise, handle with .catch
reject(error);
} else {
console.log(response.statusCode, body);
fulfill(body);
}
});
});
}
That can be called as
// var self = this; // why? not needed in the code shown
// var returnPromise; // why? it's not needed in the code shown
this.httpService.testService()
.then(function(result) {
console.log(result);
})
.catch(function(err) {
// handle your errors here
});

Categories

Resources