Understanding HTTP function inside Alexa Skill-- JavaScript - javascript

I am currently learning how to connect my Amazon Lambda function (in js) to an API. I found the following code which works but I am new to javascript and APIs in general and am not sure what it is doing. Could someone explain to me what this function does and how it works? Thanks!
function httpGet() {
return new Promise(((resolve, reject) => {
var options = {
host: 'api.icndb.com',
port: 443,
path: '/jokes/random',
method: 'GET',
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}

Here the response object is a node.js stream, a 'push' stream in particular. (This article does a good job of explaining push/pull streams).
const request = https.request(options, (response) => {
// Your request has been successfully made and you are
// handed a response object which is a stream, which will emit
// a 'data' event when some data is available.
response.setEncoding('utf8');
let returnData = '';
// A chunk of data has been pushed by the stream,
// append it to the final response
response.on('data', (chunk) => {
returnData += chunk;
});
// All the data has been pushed by the stream.
// 'returnData' has all the response data. Resolve the
// promise with the data.
response.on('end', () => {
resolve(JSON.parse(returnData));
});
// Stream has thrown an error.
// Reject the promise
response.on('error', (error) => {
reject(error);
});
});
request.end();

I found a better solution. Create a function to getRemoteData and/or postRemoteData.
getRemoteData (url) {
return new Promise((resolve, reject) => {
axios
.get(url)
.then(res => {
console.log(res.data);
resolve(res.data);
})
.catch(error => {
console.error(error);
});
})
},
postRemoteData (url, body) {
return new Promise((resolve, reject) => {
axios
.post(url, body)
.then(res => {
console.log(res.data);
resolve(res.data);
})
.catch(error => {
console.error(error);
});
})
},
Then use these functions in your IntentsHandlers.
//Get
const url = "https://anydir.com"
let speakOutput = "No data";
await logic.getRemoteData(url)
.then((data) => {
speakOutput = data.results.toString();
})
//Post
const url = "https://anydir.com"
let speakOutput = "No data";
await logic.getRemoteData(url, {param1:valueParam1,param2:valueParam2})
.then((data) => {
speakOutput = data.results.toString();
})
Example.
const NumberCharactersIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'NumberCharactersIntent';
},
async handle(handlerInput) {
const url = "https://rickandmortyapi.com/api/character"
let speakOutput = "No data";
await logic.getRemoteData(url)
.then((data) => {
speakOutput = `There are ${data.results.length.toString()} in the Rick and Morty serie`
})
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};

Related

test http.request with options using jest

Im learning using Jest and i faced this function,
but not sure how to start testing, it has inside an http.request({}, (res) => {})
and not sure how can i mock this http.request inside the current function:
also the resolve and reject from the current promise,
in advance Thank You!
const options = {
hostname: 'myHostName'
port: 'myPort',
path: 'myPath',
method: 'GET'
};
function myRequest(options) {
return new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
if (res.statusCode === 200) {
let responseData = '';
res.on('data', (data) => {
responseData += data;
});
res.on('end', () => {
const response = JSON.parse(responseData);
resolve([response, true]);
});
} else {
reject(`res.message`);
}
});
req.on('error', (error) => {
reject(error);
});
req.end();
});
}

How to mock https.get with Jest

I have a function that calls https.get inside a promise which I want to test with Jest.
The function is like this:
const request = (url) => {
return new Promise((resolve, reject) => {
const chunks = [];
https.get(url, (stream) => {
stream
.on('data', (chunk) => {
if( chunk ) {
chunks.push(JSON.parse(chunk));
}
})
.on('error', (err) => {
reject(err);
})
.on('end', () => {
const data = doSomething(chunks);
resolve(data)
});
});
})
}
I want to test that when the function resolves on "end" and rejects on "error";
Currently I have a test like this but because .on("end") doesn't get called, the promise never resolves.
describe("request", () => {
it("Should resolve", async (done) => {
const response = await request("my-url");
expect(response).toEqual("some-data")
})
})
How can I mock events like .on("end") to be called and ensure the promise resolves?
You can do something like this.
// ./request.test.js
jest.mock('https', () => ({
methodToMock: {}
}));
const Stream = require('stream');
const request = require("./request");
const httpsMock = require("https");
describe("request", () => {
it("Should resolve", async () => {
var streamStream = new Stream()
httpsMock.get = jest.fn().mockImplementation((url, cb) => {
cb(streamStream)
streamStream.emit('data', 'some');
streamStream.emit('data', '-');
streamStream.emit('data', 'data');
streamStream.emit('end'); // this will trigger the promise resolve
})
const response = await request("my-url");
expect(response).toEqual("some-data");
})
})
const https = require("https");
const request = (url) => {
return new Promise((resolve, reject) => {
const chunks = [];
https.get(url, (stream) => {
stream
.on('data', (chunk) => {
if (chunk) {
// chunks.push(JSON.parse(chunk));
chunks.push(chunk);
}
})
.on('error', (err) => {
reject(err);
})
.on('end', () => {
// const data = doSomething(chunks);
const data = chunks.join('');
resolve(data)
});
});
})
}
module.exports = request;
Note that jest.mock('https', ...) need to be called before const request = require("./request"); if you want https to be mocked.

Promise returns wrong value

In my code I try to assign a value to json variable to return it after (because I can't return it from the anon. function).
As my function is async, because it sends requests (maybe someone knows how to make it sync? I didn't plan to make it asynchronous), I've added await before the request (https.get).
I've been trying to get value from the Promise, but it's always undefined, even though I've awaited the async function.
Here's a code:
async function get_users() {
const https = require('https');
var token = '...';
var json = undefined;
await https.get('...', (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
json = JSON.parse(data)['response']['items'];
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
return json;
}
get_users().then(function(result) {
console.log(result);
});
Return a Promise and resolve it, when the end event is called, otherwise reject it in case of an error occurred:
async function get_users() {
const https = require('https');
const token = '...';
return new Promise((resolve, reject) => {
https.get('...', resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
resp.on('end', () => {
let json;
try {
json = JSON.parse(data)['response']['items'];
} catch (e) {
reject(e);
};
resolve(json);
});
}).on("error", err => reject(err));
});
}
get_users().then(result => console.log(result));
Please refer my below code.I had issues with getting responses from Promises too.But i finally got it to work.Here's the code:
var output;
var rp = require('request-promise-native');
var myJSONObject = {
"inputs": [{
"name": "<name>",
"value": < value >
}]
};
var orchName = 'TEST05';
postData = JSON.stringify(myJSONObject);
return networkCall(postData, orchName).then((response) => {
console.log('response is' + response)
}).catch((response) => {
console.log(`ERROR: ` + response);
});
function networkCall(postData, orchName) {
return new Promise((resolve, reject) => {
var options = {
method: 'post',
uri: '<URL>',
body: postData,
auth: {
'user': 'usr',
'pass': 'pwd'
},
json: true
};
return rp(options)
.then(body => {
var response = body;
resolve(response);
})
.catch(err => {
console.log('FAILED' + err);
reject(err);
});
});
}
This way your code can run in Synchronous Flow.If the return value is undefined,then,what might have probably happened is that the calling function would have finished executing even before the called function returns its response.But the above approach would work just fine.

Writing a generic HTTP request in NodeJS

I am making an app that creates multiple HTTP requests to different APIs, and would like to abstract the "sending" and "getting" portion of the data into a utility function that can be exported. It should be async. So far, I have created the following, but it won't work since request.end() needs to be declared somewhere, and I'm stuck here. Thanks!
Note: the resulting data should be able to be easily returned to some other function on order to do other work with it later on.
exports.handleHttpRequests = (url) => {
return new Promise((resolve, reject) => {
const request = http.request(url, response => {
let chunks = [];
res.on('data', chunk => {
chunks.push(chunk);
});
res.on('end', () => {
let body = Buffer.concat(chunks).toString();
resolve(body);
})
})
}).then(data => {
return data;
});
}
Hey you already done all, just call request.end() inside your new Promise callback & also handle error . And do what you want to do with resolve ,reject.
exports.handleHttpRequests = (url) => {
return new Promise((resolve, reject) => {
const request = http.request(url, res => {
let chunks = [];
res.on('data', chunk => {
chunks.push(chunk);
});
res.on('end', () => {
let body = Buffer.concat(chunks).toString();
resolve(body);
})
});
//handling error
request.on('error', (e) => {
reject('problem with request: ' + e.message);
});
//here you have to put request.end()
request.end();
})
};

await http request response in constructor

I have a class, how I can create await for key value, that should be requested from http request in another method?
I don't know how to correct use await in this situation.
Here code, it returns only undefined:
class MyClass {
constructor(key = null) {
if (!!key)
this.key = key;
else
(async () => { this.key = await this.getKey(); })();
}
getKey(input) {
return new Promise((resolve, reject) => {
let options,
request,
data = '';
try {
options = {
host: '...',
port: '80',
path: '/',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
request = http.request(options, (response) => {
response.setEncoding('utf8');
response.on('data', (chunk) => {
data += chunk.toString();
});
response.on('end', () => {
resolve(new RegExp('<div id="...".*>(.*)<\/div>', 'g').exec(data)[1]);
});
});
request.end();
} catch (error) {
reject(error);
}
});
}
}
a better usage would be to use await for the var you'll put in parameter :
let key = await getKey();
let myClass = new MyClass(key);
Perhaps I'm as confused about async await as you are, but it doesn't really seem necessary in this scenario.
class MyClass {
initKey() {
this.getKey().then(d => { this.key = d })
}
getKey(){
return new Promise((resolve, reject) => {
resolve("the promised value")
})
}
}
let t = new MyClass()
t.initKey()

Categories