DEV Community

Scott Lepper
Scott Lepper

Posted on

12 7

Http Request with AWS Lambda, Node.js 8.10, and Standard http library

In my previous article I showed an approach to extend a "traditional" (monolithic architecture) app using AWS Lambda: https://dev.to/scottlepp/extending-traditional-software-with-serverless-microservices-442m

Let's take a closer look at the Lambda function and how to make an http request using Node.js 8.10 and the standard http library.

In previous versions of node.js, the handler function contained a callback argument like so:

exports.handler = function (event, context, callback) {
Enter fullscreen mode Exit fullscreen mode

And when your http request finished you would execute the callback to indicate the function was finished:

const req = http.request(options, (res) => {
   callback('Success');
});
Enter fullscreen mode Exit fullscreen mode

And yet even older version of node.js didn't have a callback function, instead you would use "context.succeed" like so:

const req = http.request(options, (res) => {
   context.succeed();
});
Enter fullscreen mode Exit fullscreen mode

However, in node.js 8.10 this has changed. The callback argument is again not needed. Now you just wrap your function returning a Promise. Then instead of executing the callback function, you execute the Promise resolve function (or reject function if it fails) as so:

const http = require('http');

exports.handler = async (event, context) => {

    return new Promise((resolve, reject) => {
        const options = {
            host: 'ec2-18-191-89-162.us-east-2.compute.amazonaws.com',
            path: '/api/repos/r1639420d605/index?delta=true&clear=false',
            port: 8000,
            method: 'PUT'
        };

        const req = http.request(options, (res) => {
          resolve('Success');
        });

        req.on('error', (e) => {
          reject(e.message);
        });

        // send the request
        req.write('');
        req.end();
    });
};
Enter fullscreen mode Exit fullscreen mode

That's it! These changes between versions of node.js tripped me up a bit so I wanted to share the latest method. Hope this helps someone!

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (8)

Collapse
 
jsiesquen profile image
Juan Siesquen • Edited

Hi Scott,

I'm using the request-promise library but when try insert within exports.handler this aren't work... this is part of code, your support please, I'm novice yet:

const rp = require('request-promise');
const rq = require('request');
require('dotenv').config();
let endpointFeed = `https://domain.com/feed/orders/status?limit=10`;
let endpointOrderSeller = `https://domain.com/orders/`;
let requestConfiguration = {
method: 'GET',
json: true,
resolveWithFullResponse: false,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/vnd.vtex.ds.v10+json',
'X-VTEX-API-AppKey': `xxxxxxxxxxxxxxxx`,
'X-VTEX-API-AppToken': `xxxxxxxxxxxxxxxxxxxxxxxx`
}
};
let noValidOrders = [];
let validOrders = [];
exports.handler = function(event, context) {
/* Get Orders Feed */
rp(endpointFeed, requestConfiguration)
.then((response) => {
if (response.length) {
response.forEach(element => {
if (['payment-completed']
.findIndex(value => value == element.status) >= 0) {
validOrders.push({
id: element.orderId,
status: element.status,
commitToken: element.commitToken
});
}
else {
noValidOrders.push({
id: element.orderId,
status: element.status,
commitToken: element.commitToken
});
}
});
}
return validOrders;
})
.then(async (orders) => {
getOrderDetails(orders);
})
.catch((handleError) => {
console.log("[Get Orders Feed: Error]: ", handleError.StatusCodeError, handleError.StatusCodeError);
throw handleError;
});
};
/* Get Order's Product Code */
let getOrderDetails= (orders) => {
let promises = [];
orders.forEach(function(order) {
requestConfiguration.url = endpointOrderSeller + order.id;
requestConfiguration.resolveWithFullResponse = true;
var promise = new Promise((resolve, reject) => {
rq(requestConfiguration, (error, response, body) => {
if (body.error === undefined) {
let products = body.items;
if (products !== undefined) {
let result = { product: [],
orderPurchaseDate: body.creationDate,
orderId: body.marketplaceOrderId
};
products.forEach(function(item, index, array) {
result .product.push({item: item.id, productName: item.name});
});
if (result.product.length)
return resolve(result);
else
return reject();
}
}
});
});
promises.push(promise);
});
Promise.all(promises)
.then((productCodes) => {
console.log('[GET Products Code]:', productCodes);
console.log(productCodes); // Final result
})
.catch((error) => {
console.log('[GET Products Code: Error]:', error);
});
};
view raw index.js hosted with ❤ by GitHub

How can implement this requests into lambda function?.... in my local test this work!

Or maybe should reemplace the requet-promise reference per a simple "http.request"?? Opinions please?

Thanks very much for advance.....

Regards

Collapse
 
jsiesquen profile image
Juan Siesquen • Edited

Hi Guys,

Finally, as I not know much about "request-promise" module, use "request-promise-native" instead. I have this model...

let msurls = ["http://example.org", "http://example.org"]
let request = require ("request-promise-native")
async function doRequests () {
    return await (Promise.all (
        msurls.map (async msurl => await request (msurl)))
    )
}
doRequests (). then (msresult => console.log (msresult))

You already have an array with the results and the code looks synchronous.

I hope that is model can use for others verbs like post and patch. I'm in testing yet. Will I do well?

Collapse
 
adamshechter9 profile image
Adam Shechter

Awesome!
thank you, this is exactly what I needed.

Collapse
 
fcpauldiaz profile image
Pablo Díaz

Nice and clean!

Collapse
 
nicolasmorinpomerleau profile image

In case of Lambda project, what urls we put in host and path parameters ?

Collapse
 
scottlepp profile image
Scott Lepper

In this case I was running Voyager Search on an ec2 instance. The host was the ec2 instance and the path was to a REST call that Voyager Search supports, but you could take this approach with any REST provider.

Collapse
 
liambarnettit profile image
Liam Barnett

Useful post - thanks!

Collapse
 
lucallero profile image
Luciano Callero

Helpful indeed, thanks!

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay