how to use async await with https post request - node.js

I am finding way out to use async / await with https post. Please help me out. I have posted my https post code snippet below.how do I use async await with this.
const https = require('https')
const data = JSON.stringify({
todo: 'Buy the milk'
})
const options = {
hostname: 'flaviocopes.com',
port: 443,
path: '/todos',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', (d) => {
process.stdout.write(d)
})
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()

Basically, you can write a function which will return a Promise and then you can use async/await with that function. Please see below:
const https = require('https')
const data = JSON.stringify({
todo: 'Buy the milk'
});
const options = {
hostname: 'flaviocopes.com',
port: 443,
path: '/todos',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
},
};
async function doSomethingUseful() {
// return the response
return await doRequest(options, data);
}
/**
* Do a request with options provided.
*
* #param {Object} options
* #param {Object} data
* #return {Promise} a promise of request
*/
function doRequest(options, data) {
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', (chunk) => {
responseBody += chunk;
});
res.on('end', () => {
resolve(JSON.parse(responseBody));
});
});
req.on('error', (err) => {
reject(err);
});
req.write(data)
req.end();
});
}

I had this problem also, found this post, and used the solution from Rishikesh Darandale (here).
The await documentation states The await operator is used to wait for a Promise. Returning the promise from a function is not required. You can just create a promise and call await on it.
async function doPostToDoItem(myItem) {
const https = require('https')
const data = JSON.stringify({
todo: myItem
});
const options = {
hostname: 'flaviocopes.com',
port: 443,
path: '/todos',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
},
};
let p = new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', (chunk) => {
responseBody += chunk;
});
res.on('end', () => {
resolve(JSON.parse(responseBody));
});
});
req.on('error', (err) => {
reject(err);
});
req.write(data)
req.end();
});
return await p;
}

You can use async-await with Promises only and Node's core https module does not have build in promise support. So you first have to convert it into the promise format and then you can use async-await with it.
https://www.npmjs.com/package/request-promise
This module has converted the core http module into promisified version. You can use this.

Related

Wait for http post to end using promise

I am learning to use http post and trying to wait for it to end using promise. But I can't get it to work, please help:
var http = require('http');
const auth = () => {
var post_data = JSON.stringify({
"username": "aaa",
"password": "bbb"
});
const options = {
host: 'http://1.1.1.1',
path: '/v1/authentication',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
};
const req = http.request(options, (res) => {
res.setEncoding('utf8');
var body = '';
res.on('data', d => {
body += chunk;
});
res.on('end', function() {
console.log("Response body", body);
});
});
req.on('error', error => {
console.error("error", error);
});
req.write(post_data)
req.end();
return Promise.resolve("!!");
};
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
return auth().then((res)=>{
res.status(200).send(res);
});
};
Entry point is the hellWorld function. What should I do to wait for the http post to finish and get the response result using promise?
here i did some for get api call.
try {
const auth = () => {
return new Promise((resolve, reject) => {
const options = {
host: 'api.github.com',
path: '/orgs/nodejs',
port: 443,
method: 'GET',
headers: {
'User-Agent': 'request'
}
};
const req = https.request(options, (res) => {
res.setEncoding('utf8');
res.on('data', d => {
resolve(d)
});
});
req.on('error', error => {
console.error("error", error);
});
req.end();
})
};
const data = await auth()
console.log('should execute first', data)
console.log('should executed after http call')
} catch (e) {
console.log(e)
}
you can modify above code with your, just you have to wrap your http call inside Promises.
comment down if any its a solution, and mark as a solution

How to chain http.request()

I need to use require('http') (I cannot use other libraries), and I am trying to figure out how I would chain multiple http.request() together?
In my example below, I am trying to create a household with 4 people, and each person will have a pet associated to them. I have 3 routes that will createFamily, createPerson, and createPet. I also have the method createHousehold() that will take the ID's from the response of each route, and pass it down the chain (family -> person -> pet). I am not sure how I would be chaining the response of each route, and passing down the ID.
const http = require('http');
createHousehold('Smith', 4); // Creates 'Smith' family with 4 people, and each member has one pet
// Not sure how to chain requests
function createHousehold(surname, numberOfPeople) {
createFamily(surname)
.then(familyId => {
for (let i = 0; i < numberOfPeople; i++) {
createPerson(familyId)
.then(personId => createPet(personId));
}
});
}
function createFamily(surName) {
const data = JSON.stringify({
config: { surName }
});
const options = {
host: 'myProxyHost.com',
port: '8080',
path: '/v1/family',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
return (response.on('end', () => JSON.parse(data).id));
});
request.on('error', error => console.log('ERROR - createFamily(): ', error.message));
request.write(data);
request.end();
return request;
}
function createPerson(familyId) {
const data = JSON.stringify({
config: { familyId }
});
const options = {
host: 'myProxyHost.com',
port: '8080',
path: '/v1/person',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
return (response.on('end', () => JSON.parse(data).id));
});
request.on('error', error => console.log('ERROR - createPerson(): ', error.message));
request.write(data);
request.end();
return request;
}
function createPet(personId) {
const data = JSON.stringify({
config: { personId }
});
const options = {
host: 'myProxyHost.com',
port: '8080',
path: '/v1/pet',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
return (response.on('end', () => JSON.parse(data).id));
});
request.on('error', error => console.log('ERROR - createPet(): ', error.message));
request.write(data);
request.end();
return request;
}
For example with a proxy server, you would pipe one request (readable) into another request (writable).
If you are just doing serial requests, I would just wrap them in a promise, or use the async library.
function createPet(personId) {
return new Promise((resolve,reject) => {
const data = JSON.stringify({
config: { personId }
});
const options = {
host: 'myHost.com',
port: '8080',
path: '/v1/pet',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
response.once('end', () => resolve(data)); // ! resolve promise here
});
request.once('error', err => {
console.log('ERROR - createPet(): ', err.message || err);
reject(err); // ! if promise is not already resolved, then we can reject it here
});
request.write(data);
request.end();
});
}
and use it like so:
createHousehold(id)
.then(createFamily)
.then(createPerson)
.then(createPet);
if you want to do things in parallel, then use Promise.all()..or use the async library.
For seeding a database, I highly recommend async.autoInject, you will quickly see why:
https://caolan.github.io/async/v2/docs.html#autoInject
you can use it like so:
const seedDatabase = () => {
return async.autoInject({ // returns a promise
async createHouseHold(){
return somePromise();
},
async createFamily(createHouseHold){
return somePromise();
},
async createPerson(createFamily){
return somePromise();
},
async createPet(createPerson){
return somePromise();
}
});
}

how to call rest api inside aws lambda function using nodejs

i have created aws lambda function. i want to use rest api calls inside my lambda function.
Is there any reference how to connect it to rest api using nodejs
const https = require('https')
// data for the body you want to send.
const data = JSON.stringify({
todo: 'Cook dinner.'
});
const options = {
hostname: 'yourapihost.com',
port: 443,
path: '/todos',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
},
};
const response = await doRequest(options, data);
console.log("response", JSON.stringify(response));
/**
* Do a request with options provided.
*
* #param {Object} options
* #param {Object} data
* #return {Promise} a promise of request
*/
function doRequest(options, data) {
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
res.setEncoding("utf8");
let responseBody = "";
res.on("data", (chunk) => {
responseBody += chunk;
});
res.on("end", () => {
resolve(JSON.parse(responseBody));
});
});
req.on("error", (err) => {
reject(err);
});
req.write(data);
req.end();
});
}
If you want to call rest api inside lambda function, you can use request package:
install request package via npm: https://www.npmjs.com/package/request
Then inside lambda function try this to call rest api:
var req = require('request');
const params = {
url: 'API_REST_URL',
headers: { 'Content-Type': 'application/json' },
json: JSON.parse({ id: 1})
};
req.post(params, function(err, res, body) {
if(err){
console.log('------error------', err);
} else{
console.log('------success--------', body);
}
});
const superagent = require('superagent');
exports.handler = async(event) => {
return await startPoint(); // use promise function for api
}
function startPoint(){
return new Promise(function(resolve,reject){
superagent
.get(apiEndPoint)
.end((err, res) => {
...
});
})
}
If you are asking about creating a HTTP rest endpoint in lambda using
nodejs. Here is the example.
https://github.com/serverless/examples/tree/master/aws-node-simple-http-endpoint
If you are asking about access an external API inside lambda using
nodejs. Here is an example.
https://github.com/robm26/SkillsDataAccess/blob/master/src/CallService/index.js
Hope this helps.

NodeJS: callback not a function

I've checked the other questions but none form an answer to mine. In other words: no answer works.
I've got two modules: app and logic. App passes a callback to logic, which logic then calls. However I get the error "cb is not a function". That's it, no more information.
This is the function in app.js that poses the callback:
app.get('/assignments/open/:student', function (request, response) {
var callback = function(mail, jobtitle) {
response.status(200).json(logic.getOpenAssignments(request.params.student));
}
logic.examine(request, callback);
});
This is the function in logic.js that calls the callback:
examine: function (request, cb) {
var options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
var req = http.get(options, function(res) {
res.on('data', function(chunk) {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
},
Any solutions? Thanks in advance!
Edit:
Following code doesn't work:
examine: function (request, cb) {
var options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
var req = http.get(options, res => {
res.on('data', chunk => {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
},
Following code also doesn't work, does this mean the scope is not the problem?
examine: function (request, cb) {
var options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
cb('hehe', 'hoho');
},
If you're using ES6, try to use arrow function to pass the scope to http.get's callback function:
var req = http.get(options, res => {
res.on('data', chunk => {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
Or you could also pass cb to your callback function :
var req = http.get(options, function(res, cb) {
res.on('data', function(chunk, cb) {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
Maybe the issue is, you are not waiting for data chunk to process. Try the following snippet. Added a way to convert http.get to promises(very common) and this avoids passing all the messy callbacks.
//put this somewhere inside where examine is located.
logic.httpGet = options => {
return new Promise((resolve, reject) => {
http.get(options, res => {
res.setEncoding('utf8');
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => resolve(body));
}).on('error', reject);
});
};
//convert your route like this
app.get('/assignments/open/:student', function (request, response) {
cont options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
return logic
.httpGet(options)
.then((data)=>{
const data =JSON.parse(data);
//i don't see where you use the processed data but do whatever you want below here
repsonse.status(200).json(logic.getOpenAssignments(request.params.student))
})
})

How to wait for the pipe to finish in form-data node.js module?

Using the form-data module in node.js, you can do this
form.pipe(request)
to put the form data to the request. But how can you wait until it is complete? Is there a callback like this
form.pipe(request).done(function(err) {});
Does anyone know?
Thanks
In the docs, they use:
form.pipe(request);
request.on('response', function(res) {
console.log(res.statusCode);
});
What I ended up doing to get my tests to work:
app.js
// form is declared
return await new Promise((resolve, reject) => {
const req = https.request(
process.env.HOST,
{
method: 'POST',
headers: form.getHeaders()
},
(res) => {
let data = '';
res.on('data', (d) => {
data += d;
});
res.on('end', () => {
resolve({
statusCode: res.statusCode,
body: data,
});
});
},
).on('error', reject);
form.pipe(req);
});
and
test-handler.js
sinon.replace(https, 'request', (url, options, callback) => {
const request = new EventEmitter();
request.on('pipe', () => {
const res = new EventEmitter();
res.statusCode = 200;
callback(res);
res.emit(
'data',
JSON.stringify({}),
);
res.emit('end');
});
return request;
});
I understand that it doesn't strictly answer your question in that the "pipe" event fires when the pipe begins and not when it's complete, but in terms of testing I don't know how to otherwise make the response finish.

Resources