Handle multipart/form-data with Serverless? - multipartform-data

How to handle multipart/form-data with serverless-framework? v.0.5.6
Just tried this:
"requestTemplates": {
"multipart/form-data": {
"httpMethod": "$context.httpMethod",
"body": "$input.json('$')",
"queryParams": "$input.params().querystring",
"headerParams": "$input.params().header",
"headerParamNames": "$input.params().header.keySet()",
"contentTypeValue": "$input.params().header.get('Content-Type')"
},
"application/json": {
"httpMethod": "$context.httpMethod",
"body": "$input.json('$')",
"queryParams": "$input.params().querystring",
"headerParams": "$input.params().header",
"headerParamNames": "$input.params().header.keySet()",
"contentTypeValue": "$input.params().header.get('Content-Type')"
}
}
action.js:
export function respond(event, cb) {
var form = new formidable.IncomingForm();
form.parse(event, function(err, fields, files) {
if (err == null) {
var response = {
status: "true",
data: fields,
error: []
};
return cb(null, response);
} else {
console.log(err);
return cb(null, ApiErrors.errors(402, err['message'] + fields));
}
});
}
But got an error: errorMessage = "Cannot read property 'content-length' of undefined";

I've got this working with serverless by emulating http.ClientRequest and using a form parser tool like formidable.
I'm using lambda-proxy for the API Gateway event configuration.
const Stream = require('stream').Readable;
const Formidable = require('formidable');
module.exports.upload = ( e, ctx, cb ) => {
let form = new Formidable.IncomingForm();
let stream = new Stream();
stream.push( e.body );
stream.push( null );
// NOTE: You'll likely want to toLowerCase() at least 'Content-Type' header key
stream.headers = e.headers;
form.parse( stream, (err, fields, files) => {
// Work with your parsed form results here.
});
}

Well, I couldnt make it as multipart/form-data, so I used base64 string.
action.js:
export function respond(event, cb) {
//console.log('Received event:', JSON.stringify(event, null, 2));
var key = new Date().toISOString().substr(0, 10) + '/' + String(Date.now());
var contentType = event.body["data"].substr(0, event.body["data"].indexOf(';'));
if (!contentType.match(/(\.|\/)(gif|jpe?g|png)$/i)) {
return cb(null, 'invalid content type, gif, jpg, and png supported');
}
var data = new Buffer(event.body["data"].replace(/^image\/\w+;base64,/, ''),'base64');
var params = {
Bucket: 'your-bucket',
Key: key,
Body: data,
ContentEncoding: 'base64',
ContentType: contentType,
ACL: 'public-read'
};
s3.upload(params, function (err, data) {
if (err) {
console.log(err);
return cb(null, ApiErrors.errors(402, err['message']));
} else {
var response = {
status: "true",
data: {
url: urlPrefix + key
},
error: []
};
return cb(null, response);
}
});
}
RequestTemplate:
"requestTemplates": {
"application/json": {
"httpMethod": "$context.httpMethod",
"body": "$input.json('$')",
"header": "$input.params().header.get($header)",
"headerParam": "$input.params().header.keySet()",
"contentType": "$input.params().header.get('Content-Type')"
}
},

Related

How to retrieve multiple image from Amazon S3 using imgURL at once?

I want to retrieve list of images in one go from Amazon S3 based on image URL.
Currently I am able to fetch single image using the following code:-
AWS.config.update({
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey
});
AWS.config.region = region;
var bucketInstance = new AWS.S3();
var params = {
Bucket: bucketName,
Key: awsImgUrl
}
bucketInstance.getObject(params, function (err, file) {
if (file) {
var dataSrc = "data:" + file.ContentType + ";base64," + EncodeData(file.Body);
callbackSuccess(dataSrc);
} else {
callbackSuccess("Error");
}
});
EncodeData = function (data) {
var str = data.reduce(function (a, b) { return a + String.fromCharCode(b) }, '');
return btoa(str).replace(/.{76}(?=.)/g, '$&\n');
}
In my scenario I have multiple S3 image url like awsImgUrl1, awsImgUrl2..awsImgUrln.
How to fetch it in one go instead of one by one?
You cannot get more than one image per api call with S3. You can however make multiple calls in parallel.
Using promises this is straightforward.
var bucketInstance = new AWS.S3();
var imageKeys = [ awsImgUrl1, awsImgUrl2, awsImgUrl3];
var promisesOfS3Objects = imageKeys.map(function(key) {
return bucketInstance.getObject({
Bucket: bucketName,
Key: key
}).promise()
.then(function (file) {
return "data:" + file.ContentType + ";base64," + EncodeData(file.Body);
})
})
Promise.all(promisesOfS3Objects)
.then(callbackSuccess) // callbackSuccess is called with an array of string
.catch(function() { callbackSuccess("Error") })
You can change the way you upload the image data. Instead of uploading a single image, upload one document containing multiple image datas.
const addImageBlock = () => {
var photoBlock = [
{
imageId: 'id',
type: 'png',
body: 'data:image/png;base64,iVBORw0K...'
},
{
imageId: 'id2',
type: 'png',
body: 'data:image/png;base64,iVBORw0K...'
},
{
imageId: 'id3',
type: 'png',
body: 'data:image/png;base64,iVBORw0K...'
},
{
imageId: 'id4',
type: 'png',
body: 'data:image/png;base64,iVBORw0K...'
}
//...ect
];
s3.upload({
Key: photoBlockId + '.json',
Body: photoBlock,
ACL: 'public-read'
}, function(err, data) {
if (err) {
return alert('There was an error', err.message);
}
});
}
Then when you receive this data with one s3 call, you can loop through and render the images on the frontend,
getObject(params, function (err, file) {
imageArr = [];
if (file) {
JSON.parse(file.toString()).map((image) => {
var image = new Image();
image.src = image.body;
imageArr.push(image)
})
callbackSuccess(imageArr);
}
else {
callbackSuccess("Error");
}
});
AWS SDK does not have any method to read multiple files as once and same with console, you can not download multiple files at once.
they have only GetObject method do read a object in bucket by key only.
so in your case you have to read one by one with their key name only if you already have key names as list..
you can get summary of objects in bucket if you would like to get list of objects then put a loop to download all files.

How can i read excel sheet and upload MSSQL server in node js

I want to upload excel sheet and after submit that excel sheet need to insert data into MSSQL database and same sheet which we upload need to download.
I used Npm packages "xlsx-to-json-lc" and "xls-to-json-lc" to import excel file to json directly without converting to csv. Hope this helps...
var storage = multer.diskStorage({ //multers disk storage settings
destination: function (req, file, cb) {
cb(null, './uploads/')
},
filename: function (req, file, cb) {
var datetimestamp = dateFormat(new Date(), "yyyy~mm~dd h~MM~ss");
cb(null, '`enter code here`templete' + '-' + datetimestamp + '.' +
`enter code here`file.originalname.split('.')[file.originalname.split('.').length - 1])
filename = file.fieldname;
}
});
var upload = multer({ //multer settings
storage: storage,
fileFilter: function (req, file, callback) { //file filter
if (['xls', 'xlsx'].indexOf(file.originalname.split('.')[file.originalname.split('.').length - 1]) === -1) {
return callback(new Error('Wrong extension type'));
}
callback(null, true);
}
}).single('file');
var exceltojson;
upload(req, res, function (err) {
if (err) {
res.json({ error_code: 1, err_desc: err });
return;
}
if (!req.file) {
//res.json({ error_code: 1, err_desc: err });
return;
}
if (req.file.originalname.split('.')[req.file.originalname.split('.').length - 1] === 'xlsx') {
exceltojson = xlsxtojson;
} else {
exceltojson = xlstojson;
}
try {
exceltojson({
input: req.file.path,
output: null, //since we don't need output.json
//lowerCaseHeaders: true
}, function (err, result) {
if (err) {
return res.json({ error_code: 1, err_desc: err, data: null });
}
else {
console.log(result);
}
});
})

Processing http post array, display undefined

I have the big problem. I want to display this json, but returning undefined value.
{"StatusCode":0,"StatusMessage":"OK","StatusDescription":{ "datas": [
{"sensor_serial":"SensorSerial1", "id":"11E807676E3F30B5"},
{"sensor_serial":"sensorserial2", "id":"11E807679D82841L"},
{"sensor_serial":"sensorserial3", "id":"11E80767A5CD2820"} ]
,"home_id":"11E80768K", "active":0, "homebox_id":"11E8076792BD0164J",
"date_created":"2018-02-01T15:55:54.000Z", "date_modified":null,
"serial_number":"serialn1", "user_id":"3"} }
I use this code in service.ts
public getHomeboxPById(id: string): Observable<HomeboxP> {
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let urlSearchParams = new URLSearchParams();
urlSearchParams.append('home_id', id);
urlSearchParams.append('token', this.auth.getCurrentUser().token);
let body = urlSearchParams.toString();
return this.http.post(Api.getUrl(Api.URLS.getHomeboxPById), body, {
headers: headers
})
.map((response: Response) => {
let res = response.json();
if (res.StatusCode === 0) {
return new HomeboxP(res.StatusDescription[0]);
} else if (res.StatusCode === 1) {
this.auth.logout();
} else {
return new HomeboxP(null);
}
});
}
In ts code I call this method getHomeboxPById, like this
editHomeboxPForm: FormGroup;
homeboxp: HomeboxP;
this.editHomeboxPForm = this.fb.group({
'homebox_id': new FormControl('', Validators.required)
});
}
populateFormHomeboxP() {
this.activatedRoute.params.subscribe(
params => {
this.ws.getHomeboxPById(params['id']).subscribe(
homeboxp => {
console.log(homeboxp); // display undefined
this.homeboxp = homeboxp;
this.editHomeboxPForm.controls['homebox_id'].setValue(homeboxp.homebox_id);
}
);
}
);
}
Please, can you help me, why doesn't work?
{"StatusCode":0,"StatusMessage":"OK","StatusDescription":{ "datas": [
{"sensor_serial":"SensorSerial1", "id":"11E807676E3F30B5"},
{"sensor_serial":"sensorserial2", "id":"11E807679D82841L"},
{"sensor_serial":"sensorserial3", "id":"11E80767A5CD2820"} ]
,"home_id":"11E80768K", "active":0, "homebox_id":"11E8076792BD0164J",
"date_created":"2018-02-01T15:55:54.000Z", "date_modified":null,
"serial_number":"serialn1", "user_id":"3"} }
If this is the response of
this.http.post(Api.getUrl(Api.URLS.getHomeboxPById)
Then issue is res.StatusDescription[0] , it should be res.StatusDescription like :
new HomeboxP(res.StatusDescription);

In NodeJS, convert database query output to Json format

This is my code:
oracledb.getConnection(
{
user : "user",
password : "password",
connectString : "gtmachine:1521/sde1"
},
function(err, connection)
{
if (err) { console.error(err); return; }
connection.execute(
"SELECT filetype, filetypeid from filetype where filetypeid < 6",
function(err, result)
{
if (err) { console.error(err); return; }
response = result.rows;
console.log(response);
res.end(JSON.stringify(response));
});
This is the output
[["Ascii Text",1],["Binary",2],["Graphics - GIF",3],["Graphics - JPEG",4],["HTML",5]]
But my front end angularjs is expecting something in this format:
[{"filetype":"Ascii Text","filetypeid":1},{"filetype":"Binary","filetypeid":2}]
Does any one know what is the standard way to convert this?
These will convert your array of arrays into an array of objects:
var results = [["Ascii Text",1],["Binary",2],["Graphics - GIF",3],["Graphics - JPEG",4],["HTML",5]];
results = results.map(
function(item) {
return {
filetype: item[0],
filetypeid: item[1]
}
}
);
console.log(results);
And in ES6:
var results = [["Ascii Text",1],["Binary",2],["Graphics - GIF",3],["Graphics - JPEG",4],["HTML",5]];
results = results.map(item => ({filetype: item[0], filetypeid: item[1]}));
console.log(results);

Add image array in existing array node

See my code below.
exports.myexports = (req, res) => {
var arrayname = new Array();
Hello.find({},function(error,fetchAllHellos)
{
if(fetchAllHellos)
{
async.eachSeries(fetchAllHellos, function(Hello, callback)
{
var hArr = {};
var image = {};
hArr['_id'] = Hello._id;
hArr['myname'] = Hello.name;
/* Use asyn Parallel method for waiting those functions value */
async.parallel
(
[
function(callback)
{
fetchingDetails(Hello._id, function(err, fetchAllDetails)
{
bArr['address'] = fetchAllDetails;
async.eachSeries(fetchAllDetails, function(fetchAllDetails, callback)
{
async.parallel
(
[
function(callback)
{
fetchingMyImage(fetchAllDetails._id, function(err, wer)
{
image[fetchAllDetails._id] = wer;
callback(err); //Forgot to add
})
}
],
function(err)
{
//console.log(image);
arrayname.push(image);
//bArr['image'] = image
callback(err);
}
);
});
callback(err); //Forgot to add
});
}
],
function(err)
{
arrayname.push(hArr);
callback(err);
}
)
},
function(err)
{
console.log(arrayname); //This should give you desired result
});
}
else
{
return res.json({"status":'error'})
}
});
};
function fetchingMyImage(mid, callback)
{
UserImage.find({myid:mid},function(error,fetchallImages)
{
callback(error,fetchallImages);
});
}
I want like this array
user
[
id = 'lkjlk',
myname = 'helloname'
address = [
object,
]
image = [
myid = image.png
]
]
Made changes in your code. Let me know if it helps you.
Please go through the code and let me know, whether you understood the changes or not.
exports.myexports = (req, res) => {
var arrayname = new Array();
Hello.find({},function(error,fetchAllHellos)
{
if(fetchAllHellos)
{
async.eachSeries(fetchAllHellos, function(Hello, callback)
{
var hArr = {};
var image = [];
hArr['_id'] = Hello._id;
hArr['myname'] = Hello.name;
//Read doc before you can start using.
async.parallel
([
function(callback)
{
fetchingDetails(Hello._id, function(err, fetchAllDetails)
{
bArr['address'] = fetchAllDetails;
async.eachSeries(fetchAllDetails, function(eachDetail, callback)
{
fetchingMyImage(eachDetail._id, function(err, wer)
{
image.push({eachDetail._id : wer;
callback(err);
})
}, function(err)
{
console.log(image);
arrayname.push({images :image});
callback(err);
});
});
}
],
function(err)
{
arrayname.push(hArr);
callback(err);
})
},
function(err)
{
console.log(arrayname); //This should give you desired result
console.log(arrayname.images)// Array of images will be consoled here.
//callback(err);
});
}
else
{
return res.json({"status":'error'})
}
});
};
function fetchingMyImage(mid, callback)
{
UserImage.find({myid:mid},function(error,fetchallImages)
{
callback(error,fetchallImages);
});
}

Resources