如何将在Lambda上使用NodeJS丰富的对象返回到API POST请求

时间:2018-08-19 19:04:19

标签: node.js api asynchronous post aws-lambda

我正在使用Lambda / NodeJS在AWS上进行开发。作为对POST请求的响应,我试图返回一个数据对象,该对象带有预签名的URL,可以访问S3上的图像。问题是返回数据,因此实际上是作为API的响应返回的。我知道这是一个异步问题,但到目前为止仍无法解决。非常感谢您的帮助。

我有以下代码:

{
    {
        docClient.query(dbparams, function (err, data) {
            if (err) {
                console.log(err);
                _response = buildOutput(500, err);
                return callback(_response, null);
            } else {
                dataObj = data.Items;
                var createOutput = function (callback) {
                    async.forEach(dataObj, function (item, callback) {
                        setObjectUrl(item, function (err, data) {
                            if (err) {
                                console.log(err);
                            }
                            return callback(undefined, data);
                        });
                    });
                };

                createOutput(function (err, data) {
                    if (err) {
                        console.log(err);
                    }
                });
                _response = buildOutput(200, data);
                return callback(null, _response);
            }
        });
    }
}


function setObjectUrl(data, callback) {
    var s3params = {
        Bucket: s3Bucket,
        Key: 'avatars/' + data.username + '.jpg'
    };

    S3.headObject(s3params, function (err, metadata) {
        if (err && err.code === 'NotFound') {
            //console.log('geen url voor deze gebruiker gevonden');
        } else {
            data["url"] = S3.getSignedUrl('getObject', s3params);
        }
        return callback(data);
    });
}

function buildOutput(statusCode, data) {
    let _response = {
        statusCode: statusCode,
        headers: {
            "Access-Control-Allow-Origin": "*"
        },
        body: JSON.stringify(data)
    };
    return _response;
}

2 个答案:

答案 0 :(得分:0)

所有异步调用完成后,您需要调用lambda的回调。有一些不同的选项可以修复您的代码,但是我建议您使用Promise和async / await。这样不仅可以使您的代码正常工作,而且还可以使代码更具可读性,并有助于避免回调地狱。

您需要将S3呼叫包装在promise中:

function getObjectUrl(data) {
    const s3params = {
        Bucket: s3Bucket,
        Key: 'avatars/' + data.username + '.jpg'
    };

    return new Promise((resolve, reject) => {
        S3.headObject(s3params, function (err, metadata) {
            if (err) {
                //handle error
            } else {
                const signedUrl = S3.getSignedUrl('getObject', s3params);
                resolve(signedUrl);
            }
         });
     });
}

之后,您只需要循环调用已承诺的函数即可:

for(let item of data.Items) {
    item.url = await getObjectUrl(data);
}

别忘了使您的主要功能异步并配置lambda以使用NodeJS 8.10

答案 1 :(得分:0)

这就是我最终解决它的方式。感谢您的帮助。

const AWS = require('aws-sdk');
const util = require('util');

// Create reference to S3 client
var S3 = new AWS.S3({
    region: 'XXXXXXXXXXXX'
    apiversion: '2006-03-01'
});

// Lambda provided credentials
let creds = new AWS.EnvironmentCredentials('AWS'); 
const dynamoConfig = {
    credentials: creds,
    region: process.env.AWS_REGION
};

const dynamoDB = new AWS.DynamoDB.DocumentClient(dynamoConfig);
const dynamoDBGetAsync = util.promisify(dynamoDB.query).bind(dynamoDB);

// some variables we need
const ddbTable = 'database';
var _response;
var s3Bucket = 'photo-bucket';

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

    if (event.resource === '/' && event.httpMethod === "GET") {
        const username = event.queryStringParameters.userid;

        var params = {
            TableName: ddbTable,
            IndexName: 'userid-index',
            KeyConditionExpression: "#uid = :uid",
            ExpressionAttributeNames: {
                "#uid": "userid"
            },
            ExpressionAttributeValues: {
                ":uid": username
            }
        };

        let result= await dynamoDBGetAsync(params);
        for (let item of result.Items) {
            if (item.username !== undefined ||  null) {
                item.url = await getObjectUrl(item);
            }
        }
        _response = buildOutput(200, result);
        return callback(null, _response);
    }
};

function getObjectUrl(data) {
    console.log("Data: " +JSON.stringify(data));
    const s3params = {
        Bucket: s3Bucket,
        Key: 'avatars/' + data.username + '.jpg'
    };

    return new Promise((resolve, reject) => {
        S3.headObject(s3params, function (err, metadata) {
            console.log('parameters: ' + JSON.stringify(s3params));
            if (err && err.code === 'NotFound') {
                console.log(JSON.stringify(err));
            } else {
                const signedUrl = S3.getSignedUrl('getObject', s3params);
                console.log(signedUrl);
                resolve(signedUrl);
            }
         });
     });
}

function buildOutput(statusCode, data) {
    let _response = {
        statusCode: statusCode,
        headers: {
            "Access-Control-Allow-Origin": "*"
        },
        body: JSON.stringify(data)
    };
    return _response;
}