Pass parameter to node js API call? - javascript

I am generating preauthorized links for files from an S3 bucket, but would like to pass in the file name to download as a parameter.
This is what my API looks like:
reports.get('/xxx', async (req, res) => {
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
var params = {
Bucket: config.xxx,
Key: 'xxx/xxx.json',
Expires: 60 * 5
}
try {
s3.getSignedUrl('getObject', params, function (err, url) {
if(err)throw err;
console.log(url)
res.json(url);
});
}catch (err) {
res.status(500).send(err.toString());
}
});
And this is how I call it from the front end:
getPreauthorizedLink(e){
fetch(config.api.urlFor('xxx'))
.then((response) => response.json())
.then((url) => {
console.log(url);
});
}
How can I add a parameter to the API call and corresponding API method to pass the filename?

Looks like you are using express on your server side so you can simply add parameters in the request URL and then get them on the server side.
In frontend or on your client side you will call the Api like
fetch('/xxx/FileName')
And on the backend you will modify your route like
reports.get('/xxx/:fileName', ..){
var fileName = req.params.fileName
}
Also you don't want to require everytime you receive a request. So you better move var AWS = require('aws-sdk'); outside your request handler.

Related

How to use an S3 pre-signed POST url?

Actually, this is the first time that I'm using s3 for uploading files. I have heard about pre-signed urls But apparently, I can't set a limitation for file size so I found "pre-signed post urls" but it's a little bit wierd!! Surprisingly I didn't find any example. maybe it's not what I want.
I'm getting pre-signed post url from the server:
const { S3 } = require("aws-sdk");
const s3 = new S3({
accessKeyId: accessKey,
secretAccessKey: secretKey,
endpoint: api,
s3ForcePathStyle: true,
signatureVersion: "v4",
});
app.post("/get-url", (req, res) => {
const key = `user/${uuri.v4()}.png`;
const params = {
Bucket: "bucketName",
Fields: {
Key: key,
ContentType: "image/png",
},
};
s3.createPresignedPost(params, function (err, data) {
if (err) {
console.error("Presigning post data encountered an error", err);
} else {
res.json({ url: data.url });
}
});
});
The weird thing is that the url that I get is not like a pre-signed url. it's just the endpoint followed by the bucket name. no query parameter. no option.
As you might guess, i can't use this url:
await axios.put(url, file, {
headers: {
"Content-Type": "image/png",
},
});
I do not even know if I should use post or two requests.
I tried both, Nothing happens. Maybe the pre-signed post url is not like pre-signed url!
At least show me an example! I can't found any.
You are on the right track, but you need to change the method you are invoking. The AWS S3 API docs of the createPresignedPost() that you are currently using states that:
Get a pre-signed POST policy to support uploading to S3 directly from an HTML form.
Try change this method to either getSignedUrl():
Get a pre-signed URL for a given operation name.
const params = { Bucket: 'bucket', Key: 'key' };
s3.getSignedUrl('putObject', params, function (err, url) {
if (err) {
console.error("Presigning post data encountered an error", err);
} else {
res.json({ url });
}
});
or synchronously:
const params = { Bucket: 'bucket', Key: 'key' };
const url = s3.getSignedUrl('putObject', params)
res.json({ url });
Alternatively, use a promise by executing getSignedUrlPromise():
Returns a 'thenable' promise that will be resolved with a pre-signed URL for a given operation name.
const params = { Bucket: 'bucket', Key: 'key' };
s3.getSignedUrlPromise('putObject', params)
.then(url => {
res.json({ url });
}, err => {
console.error("Presigning post data encountered an error", err);
});
Please also read the notes parts of the API documentation to make sure that you understand the limitations of each method.

How to get and use temporary security credentials for multipart upload with javascript aws-sdk addressing MinIO server?

I have a MinIO server and need to write a simple web application that selects a file and performs a multipart upload with temporary security credentials. I would like to do something like described here: https://github.com/minio/minio/blob/master/docs/sts/assume-role.md for getting temporary security credentials using some user credentials i created before. But i want to do it using aws-sdk-js. And i am not sure how to do that for MinIO, like pointing to the right endpoint and using the existing user credentials to invoke AssumeRole or some other corresponding function. Afterwards i want to do a multipartupload, with which i am also struggling how to use it.
I have gone through documentation, but i am struggling to use the provided functions with MinIO in the way i want.
AssumeRole: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/STS.html
Multipart Upload: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3/ManagedUpload.html
I already set up some code to show what i want to do. multipart-upload.js creates a express server that exposes and endpoint for clients to retrieve temporary security credentials, such that i don't have to share any long-term credentials with the client.
multipart-upload.js
const AWS = require('aws-sdk')
var sts = new AWS.STS();
const server = require('express')()
server.get('/openTemporarySession', (req, res) => {
var params = {
DurationSeconds: 'NUMBER_VALUE',
SerialNumber: 'STRING_VALUE',
TokenCode: 'STRING_VALUE'
};
sts.getSessionToken(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else res.send(data); // successful response
})
})
server.get('/', (req, res) => {
res.sendFile(__dirname + '/indexmultipart.html');
})
server.listen(8080)
The client selects files and uploads them through a button. The corresponding function gets temporary security credentials from the server and sequentially performs multipart upload.
indexmultipart.html
<input type="file" id="selector" multiple>
<button onclick="upload()">Upload with minio</button>
<div id="status">No uploads</div>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
<script type="text/javascript">
var sts = new AWS.STS();
// invoke helper function to get temporary security credentials and perform multipart upload
function upload() {
// Reset status text on every upload.
$('#status').text(`No uploads`)
retrieveTempCredentials()
// Get selected files from the input element.
var files = $("#selector")[0].files
for (var i = 0; i < files.length; i++) {
var file = files[i]
uploadFile(file)
}
}
// call endpoint to generate a pre-signed URL for use in uploading file.
function retrieveTempCredentials() {
$.get(`/openTemporarySession`, (data) => {
AWS.config.credentials = sts.credentialsFrom(data);
})
}
// upload file to MinIO using the presigned url
function uploadFile(file) {
var upload = new AWS.S3.ManagedUpload({
params: {Bucket: 'bucket', Key: 'key', Body: file},
tags: [{Key: 'tag1', Value: 'value1'}, {Key: 'tag2', Value: 'value2'}]
});
}
</script>
This code does not really work and I need some help to achieve something like this since i am all new to javascript and html.

Express.js Server: PUT Request using Middleware

I have a working Node/Express server and I'm using it to do requests via localhost to an external API. As you can see in my example code, I'm using node-fetch for my basic GET requests.
For every request, I prepare a const url = BASE_URL in advance, needed for the actual external server request.
But I'm getting stuck at my PUT-Request as I can't using node-fetch. So what do I have to do, to notify my Express server with the actual URL for the PUT-Request?
The PUT-Request doesn't work til here.
/* Route: Get Appointment it's availability times */
app.get('/availability/times/:id/:date/:locationId', (req, res) => {
var id = req.params.id;
var date = req.params.date;
var locationId = req.params.locationId;
const url = BASE_URL + '/availability/times?appointmentTypeID=' + id + '&date=' + date + '&calendarID=' + locationId;;
fetch(url, {
mode: "no-cors",
method: "GET",
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'content-type'
},
})
.then(response => response.json())
.then(json => {
res.json(json);
});
});
app.put('/appointments/:id/cancel', (req, res) => {
var id = req.params.id;
const url = BASE_URL + '/appointments/' + id + '/cancel';
res.send(req.body)
});
If you're saying that fetch is undefined in your put request, make sure you are requiring it at the top before any routes var fetch = require('node-fetch'). For your base url, you should store that in a config file. Create a file called config.js that looks something like this:
module.exports = {
'BASE_URL': 'yoururlhere'
}
then require this in your express server var config = require('pathToConfig'); and you can use it by specifying config.BASE_URL
If that doesn't help, please be more specific with what your actual problem is

How to configure API endpoint to receive file from ember-uploader component

I'm trying to figure out how to use ember-uploader, I have the following component (like the one in the README)
export default EmberUploader.FileField.extend({
filesDidChange: function(files) {
const uploader = EmberUploader.Uploader.create({
url: (ENV.APP.API_HOST || '') + '/api/v1/images/',
});
console.log(uploader);
if (!Ember.isEmpty(files)) {
var photo = files[0];
console.log(photo);
uploader.upload(photo)
.then(data => {
// Handle success
console.log("Success uploading file");
console.log(data);
}, error => {
// Handle failure
console.log("ERROR uploading file");
console.log(error);
});
}
}
});
The express API endpoint is listening for a POST request.
var saveImage = (req, res, next) => {
let body = req.body;
res.json({
data: body
});
};
But the body is empty after the request is done. I really don't know how to implement the API endpoint in order to get the file, I tried to see the req object and it doesn't contains the file.
Debugging it, After select a file using the component I get the following info in the console.
Seems that the API endpoint works because I get the following output:
POST /api/v1/images/ 200 27.284 ms - 11
But I can't get the file.
SOLUTION
In Express 4, req.files is no longer available on the req object by
default. To access uploaded files on the req.files object, use a
multipart-handling middleware like busboy, multer, formidable,
multiparty, connect-multiparty, or pez.
Following this blog, the code below was added to the API and the ember-uploader code posted in the question worked as expected.
import formidable from 'formidable';
var saveImage = (req, res, next) => {
var form = new formidable.IncomingForm();
form.parse(req);
form.on('fileBegin', function (name, file){
file.path = __dirname + '/tmp/' + file.name;
});
form.on('file', function (name, file){
res.json({
data: file.name
});
});
};

How to get parameters of `req` in express node server

I have two paramaters in my UI. One is a file and another is dataObject. In the utils, I have written code as :
importPlan: function (formData, planDTO) {
return axios.post(`${importPlanAPIPath}`, planDTO, formData);
}
In the router, I am sending this as :
router.post('/plans/importPlan/', planController.importPlan);
and in the controller, I have written the request as :
async importPlan(req, res, cb) {
let plan,
planDTO = req.body;
const formData = new FormData(),
file = req.files.file;
formData.append('file', file.data);
console.log('planDTO => ', planDTO);
console.log(file.data, file.name);
try {
plan = await req.clients.planClient.importPlan(formData, planDTO);
} catch (err) {
return cb(err);
}
res.json(plan);
}
In the req.body, I am getting the planDTO but I am not getting any req.files in the req. Also I am using bodyparser to parse the request. I am also using busboybodyparser for multipart/form-data.
Can Somebody please tell what I am doing wrong?
Thanks in advance.
yourparam is parameter name
router.post('/plans/importPlan/:yourparam', planController.importPlan);
async importPlan(req, res, cb) {
var yourparam= req.params.yourparam;
..........
res.json(plan);
}
use this module for file upload https://www.npmjs.com/package/multer

Categories