How to upload file to Dropbox with axios - javascript

I need to upload file to Dropbox with axios. Here is my code:
const uploadToExternalService = async function uploadToExternalService(token, content) {
try {
let res = await axios({
url: 'https://api-content.dropbox.com/1/files_put/auto/'+'file_name',
method: 'put',
// timeout: 8000,
headers: {
Authorization: 'Bearer ' + token,
'Content-Type': 'text/plain',
body: content
}
})
if(res.status == 200){
// test for status you want, etc
console.log(res.status)
}
if(res.status == 400){
console.log(res)
}
return res.data
}
catch (err) {
console.error(err);
}
}
uploadToExternalService(SECRET_KEY, req.file).then(res => console.log(res));
I'm getting error Request failed with status code 400

Eventually I managed to find a solution using dropbox-v2-api. Hopefully this answer will provide a helpful code example for other community members although the solution was implemented w/o axios
import dropboxV2Api from "dropbox-v2-api";
import fs from "fs";
// authentication
const dropbox = dropboxV2Api.authenticate({
token: DROPBOX_SECRET_KEY
});
//configuring parameters
const params = Object.freeze({
resource: 'files/upload',
parameters: {
path: '/file_name.docx'
},
readStream: fs.createReadStream(filePath)
// filePath: path to the local file that we want to upload to Dropbox
});
let dropboxPromise = new Promise(function(resolve, reject) {
dropbox(params, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
await dropboxPromise.then(function (resultObj) {
console.log("fileUpload_OK")
}).catch(function(err){
console.log(err.message)
});

You are using dropbox v1 APIs which are officially retired. Why not use v2?
For your problem, try sending the body outside of headers
headers: {
Authorization: 'Bearer ' + token,
'Content-Type': 'text/plain'
},
body: content
corrected code:
const uploadToExternalService = async function uploadToExternalService(token, content) {
try {
let res = await axios({
url: 'https://api-content.dropbox.com/1/files_put/auto/'+'file_name',
method: 'put',
// timeout: 8000,
headers: {
Authorization: 'Bearer ' + token,
'Content-Type': 'text/plain'
},
body: content
})
if(res.status == 200){
// test for status you want, etc
console.log(res.status)
}
if(res.status == 400){
console.log(res)
}
return res.data
}
catch (err) {
console.error(err);
}
}
uploadToExternalService(SECRET_KEY, req.file).then(res => console.log(res));

The Issue
The example cURL from the Dropbox documentation is:
curl -X POST https://content.dropboxapi.com/2/files/upload \
--header "Authorization: Bearer " \
--header "Dropbox-API-Arg: {\"path\": \"/Homework/math/Matrices.txt\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}" \
--header "Content-Type: application/octet-stream" \
--data-binary #local_file.txt
--data-binary means the /upload endpoint requires the file to be send as binary data. In Axios, it seems the only way to do this is with the FormData() interface.
But, using the FormData() interface requires using Content-Type: multipart/form-data. The /upload endpoint requires Content-Type: application/octet-stream.
Therefore, I do not think uploading using Axios is possible in this situation.
The Alternative Solution
dropbox-v2-api is not an official API for Dropbox and there's no explanation I could find for uploading files more than 150MB. So, instead, I would use dropbox-sdk-js. The example they give for /upload is:
function uploadFile() {
const UPLOAD_FILE_SIZE_LIMIT = 150 * 1024 * 1024;
var ACCESS_TOKEN = document.getElementById('access-token').value;
var dbx = new Dropbox.Dropbox({ accessToken: ACCESS_TOKEN });
var fileInput = document.getElementById('file-upload');
var file = fileInput.files[0];
if (file.size < UPLOAD_FILE_SIZE_LIMIT) { // File is smaller than 150 Mb - use filesUpload API
dbx.filesUpload({path: '/' + file.name, contents: file})
.then(function(response) {
var results = document.getElementById('results');
var br = document.createElement("br");
results.appendChild(document.createTextNode('File uploaded!'));
results.appendChild(br);
console.log(response);
})
.catch(function(error) {
console.error(error);
});
} else { // File is bigger than 150 Mb - use filesUploadSession* API
const maxBlob = 8 * 1000 * 1000; // 8Mb - Dropbox JavaScript API suggested max file / chunk size
var workItems = [];
var offset = 0;
while (offset < file.size) {
var chunkSize = Math.min(maxBlob, file.size - offset);
workItems.push(file.slice(offset, offset + chunkSize));
offset += chunkSize;
}
const task = workItems.reduce((acc, blob, idx, items) => {
if (idx == 0) {
// Starting multipart upload of file
return acc.then(function() {
return dbx.filesUploadSessionStart({ close: false, contents: blob})
.then(response => response.session_id)
});
} else if (idx < items.length-1) {
// Append part to the upload session
return acc.then(function(sessionId) {
var cursor = { session_id: sessionId, offset: idx * maxBlob };
return dbx.filesUploadSessionAppendV2({ cursor: cursor, close: false, contents: blob }).then(() => sessionId);
});
} else {
// Last chunk of data, close session
return acc.then(function(sessionId) {
var cursor = { session_id: sessionId, offset: file.size - blob.size };
var commit = { path: '/' + file.name, mode: 'add', autorename: true, mute: false };
return dbx.filesUploadSessionFinish({ cursor: cursor, commit: commit, contents: blob });
});
}
}, Promise.resolve());
task.then(function(result) {
var results = document.getElementById('results');
results.appendChild(document.createTextNode('File uploaded!'));
}).catch(function(error) {
console.error(error);
});
}
return false;
}

Related

Fetch always returns 200 even when server returns 400 or some error. How to get correct result?

The bounty expires in 2 days. Answers to this question are eligible for a +100 reputation bounty.
Ganesh Putta is looking for an answer from a reputable source.
I have below function in frontend, I have to make some api call here in this function. When i checked the called function via command prompt, the server api call returns 400. but the function in frontend fetch always returning 200 instead of error.
Thanks in advance.
Please guide to how to correct response which is thrown from server call?
Here is the frontend function.
function processFile() {
var fileToLoad = document.getElementById("fileToLoad").files[0];
var url;
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) {
var rows = fileLoadedEvent.target.result.split("\n");
for (var i = 0; i < rows.length - 1; i++) {
var cells = rows[i].split(",");
//alert(cells);
console.log("AgentteamID=" + cells[0] + " SkilltargetID=" + cells[1] + " flag=" + cells[2]);
url = "/updateAgentTeam?agentTeamID=" + cells[0] + "&skillTargetID=" + cells[1] + "&flag=" + cells[2],
//alert(url);
console.log("URL=" + url);
const response = fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then(response =>
response.json().then(data => ({
data: "success",
status: response.status
})).then(res => {
var statusCode = JSON.stringify(res.status);
//$('#Success_comment').html(JSON.stringify(res)+"---"+url;);
//alert(url);
document.getElementById("Success_comment").value += JSON.stringify(res) + "---" + url;
console.log("final result " + JSON.stringify(res) + "---" + url);
}))
}
}
fileReader.readAsText(fileToLoad, "UTF-8");
}
Here is the Server side code. For now we are using only Flag A block
app.get("/updateAgentTeam", (req, res) => {
var skillTargetID = req.query.skillTargetID;
console.log("req.query.skillTargetID =" + req.query.skillTargetID);
var agentTeamID = req.query.agentTeamID;
var flag = req.query.flag;
var finalurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
var xml;
//console.log("finalurl ="+finalurl);
axios({
url: finalurl,
method: "get",
auth: {
username: "xxx",
password: "yyy"
},
})
.then(async(response) => {
xml = response.data;
//console.log("after calling xml is "+JSON.stringify(xml));
res.send(response.data);
if (flag === 'D') {
agentremovedXML = removeAgentFromXML(xml, skillTargetID);
//newxml=removeAgentFromXML(xml);
//console.log("Final Agent remove XML "+JSON.stringify(agentremovedXML));
postAgentToTeam(agentTeamID, agentremovedXML);
//setSuccessJSON();
} else if (flag === 'A') {
AgentXML = await generateAgentXML(skillTargetID);
console.log("Returned agent xml is " + JSON.stringify(AgentXML));
console.log("xml where agent to be add " + JSON.stringify(xml));
if (JSON.stringify(xml.agentCount) == 0) {
AgentXML = {
"agent": [AgentXML]
};
xml.agents = [AgentXML];
console.log("xml with zero agents " + JSON.stringify(xml));
} else {
xml.agents[0].agent.push(AgentXML);
console.log("Compare " + JSON.stringify(xml));
}
console.log("xml send to postAgentToTeam is " + xml);
postAgentToTeam(agentTeamID, xml);
//postAgentToTeam(agentTeamID,agentXML);
}
})
.catch((err) => {
res.status(400);
res.send(err.response.status);
console.log(err);
//setErrorJSON()
});
});
async function postAgentToTeam(agentTeamID, xml) {
var teamurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
//console.log("final XML is "+JSON.stringify(xml));
xml.agents = xml.agents[0].agent.map(agent => ({
agent: agent
}));
var updatedJSONwithAgentTags = JSON.stringify(xml, null, " ");
//console.log("newwwwwwwwwwwwwwwwwwwwww "+ updatedJSONwithAgentTags);
//return;
js2xml = json2xml(JSON.parse(JSON.stringify(xml)));
json2 = "<agentTeam>" + js2xml + "</agentTeam>";
//console.log("newwww converted XML "+json2);
response = await axios({
url: teamurl,
method: "put",
auth: {
username: "administrator#dcloud.cisco.com",
password: "C1sco12345"
},
data: json2,
headers: {
'Content-Type': 'application/xml; charset=utf-8'
}
})
.then(response => {
console.log("hellooo " + response.status);
})
.catch((err) => {
console.log(err.response.data.apiError);
console.log("error res is " + err.response.status);
});
}
There's a quite few things wrong.
Inside your first .then(async(response) => {, you set the xml to response.data then right away call res.send(response.data) (200) which is the end of the execution order for Express. However, you go on to do a bunch of other things after the res.send (200) is sent. You should not do that.
You need to restructure your code. Starting from the top-down keeping in mind that all promises need to be returned and that res.send() is the end of the block. Throwing a 400 after this won't matter since Express already sent the response to the client.
You're also mutating theresponse output from Axios which is bad practice. Create a new one if you need to mutate it:
const newResponse = { ...response };
Additionally, this mixing of .then().catch() with an initial await is not how you should handles promises and would cause problems.
Don't write them like this:
response = await axios({}).then().catch().
Either do this:
axios({ // <--- no await, no let response =
url: finalurl,
method: "get",
auth: {
username: "xxx",
password: "yyy"
},
})
.then(async(response) => {
// res.send, etc.
}).catch((e) => {
// handle errors
});
Or use try / catch blocks like this:
try {
const results = await axios({
url: teamurl,
method: "put",
auth: {
username: "administrator#dcloud.cisco.com",
password: "C1sco12345"
},
data: json2,
headers: {
'Content-Type': 'application/xml; charset=utf-8'
}
}); // <--- the end.
console.log({results});
} catch (e) {
// handle errors
console.log(e);
}

Copy images from one folder to another in digitalocean spaces

I am working with digital ocean spaces and I have uploaded the images on it in a temporary folder. Now I want to move that image from temporary folder to permanent folder. I have searched the things from all over but got nothing much satisfying. Is it possible to do so ?
and if yes please help me with the javascript code.
First I generated the signed url and with the help of that signed url I uploaded the image on digitalocean spaces. Following is the code for generating signed url and uploading images.
const getSignedUrl = async () => {
const body = {
fileName: 'temp/' + file.name,
fileType: file.type,
}
const response = await fetch(`${API_URL}/presigned_url`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
})
const { signedUrl } = await response.json()
return signedUrl
}
const uploadFile = async signedUrl => {
const res = await fetch(signedUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type,
'x-amz-acl': 'public-read',
}
})
return res
}
please help me how can I move my image from temporary folder to permanent folder.
So finally after searching I got the answer,
From the front end side I call an API to copy my image
const copyFile = async (file) => {
try {
const body = {
fileName: file.name
}
const res = await fetch(`${API_URL}/copy_file`, {
method: 'PUT',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
})
return res
} catch (error) {
console.log(error);
}
}
And in the backend side the API I made is
app.put('/copy_file', (req, res) => {
const fileName = req.body.fileName
console.log("body", fileName);
const params = {
Bucket: config.spaces.spaceName,
CopySource: `/bucketName/temp/${fileName}`,
Key: `original/${fileName}`,
}
spaces.copyObject(params, function (err, data) {
if (err) {
console.log("Error", err)
// console.log(err, err.stack); // an error occurred
} else {
res.json({ data })
}
});
});
This will copy you image in original folder

Trying to send an image to Oracle database, but does not open well

So, i am trying to send an image to Oracle Database, and it works, but it is not in a good format, beacuse it looks like:
Content-Disposition: form-data; name="image"; filename="1.jpg"
Content-Type: image/jpeg
//image format
and I only need the image format, without the top of it.
This is my code for POSTing the image:
const maxFileSize = 1024 * 1024 * 50; // 50 MB
let contentBuffer = [];
let totalBytesInBuffer = 0;
let contentType = req.headers['content-type'] || 'application/octet';
let fileName = req.headers['file-name'];
req.on('data', chunk => {
contentBuffer.push(chunk);
totalBytesInBuffer += chunk.length;
});
req.on('end', async function() {
contentBuffer = Buffer.concat(contentBuffer, totalBytesInBuffer);
const context = {
id: parseInt(req.params.id, 10),
file_name: fileName,
content_type: contentType,
content_buffer: contentBuffer
};
const fileId = await image.create(context);
res.status(201).json({succes: true});
}
And when I GET the image, this is the code:
const context = {
id: parseInt(req.params.id, 10)
}
const rows = await image.find(context);
if (rows.length === 1) {
res.status(200);
res.set({
'Cache-Control': 'no-cache',
'Content-Type': rows[0].content_type,
'Content-Length': rows[0].file_length,
'Content-Disposition': 'attachment; filename=' + rows[0].file_name
});
res.send(rows[0].image);
}
image.create() and image.find() are just simple SQLs.
I do not know what to do, and how to get the corect file/image.
This is the tutorial link from where I tried to make this:
https://jsao.io/2019/06/uploading-and-downloading-files-buffering-in-node-js/?unapproved=584&moderation-hash=a30eac5abf07cab32aeb6dd25cee2a1f#comment-584
Edit:
Here is my image.create:
const createSql = `insert into test_image (
id,
file_name,
content_type,
image
) values (
:id,
:file_name,
:content_type,
:content_buffer
)`;
async function create(context) {
try {
const binds = context;
result = await database.simpleExecute(createSql, binds);
return ;
} catch(err) {
console.log(err);
return err;
}
}
I hope it helps.

Postman Pre-request Script for authorization bearer token

I'm trying to make script to generate my authentication bearer token for collections. so I don't have to pass token each time and I will Inherit auth from parent. But I don't know where I'm wrong in script, I'm not able to generate token and it giving me error
There was an error in evaluating the Pre-request Script: Error: No data, empty input at 1:1 ^
Here is my script,
var expiresOn = pm.variables.get('ExpiresOn');
if (!expiresOn || new Date(expiresOn) <= new Date()) {
var clientId = '565v7677676vfdrd';
var apiToken = '6565fdvdrdfd';
var request = {
url: 'http://.../auth/token',
method: 'POST',
header: 'Content-Type:application/Json',
body: {
mode: 'application/json',
raw: clientId + apiToken
}
};
}
};
pm.sendRequest(request, function (err, res) {
if (res !== null) {
var json = res.json();
pm.environment.set('Access_Token', json.access_token)
var expiresOn = new Date(0);
expiresOn.setUTCSeconds(json.expires_on);
pm.environment.set('ExpiresOn', expiresOn);
}
});
}
const echoPostRequest = {
url: 'https://example.com/sign_in?client_id=dbdsA8b6V6Lw7wzu1x0T4CLxt58yd4Bf',
method: 'POST',
header: 'Accept: application/json\nUser-Agent: Example/2019.10.31-release (Android 6.0.1; LGE Nexus 5)\nUDID: 1d2c7e65f34b3882f8e42ab8d6a82b4b\nContent-Type: application/json; charset=utf-8\nHost: api-mobile.example.com',
body: {
mode: 'application/json',
raw: JSON.stringify(
{
client_id:'dbdsA8b6V6Lw7wzu1x0T4CLxt58yd4Bf',
client_secret:'aBK1xbehZvrBw0dtVYNY3BuJJOuDFrYs',
auth_method:'password',
create_if_not_found:false,
credentials:{identifier:'username',password:'pass'},
signature:'2:a899cdc0'
})
}
};
var getToken = true;
if (!pm.environment.get('accessTokenExpiry') ||
!pm.environment.get('currentAccessToken')) {
console.log('Token or expiry date are missing')
} else if (pm.environment.get('accessTokenExpiry') <= (new Date()).getTime()) {
console.log('Token is expired')
} else {
getToken = false;
console.log('Token and expiry date are all good');
}
if (getToken === true) {
pm.sendRequest(echoPostRequest, function (err, res) {
console.log(err ? err : res.json());
if (err === null) {
console.log('Saving the token and expiry date')
var responseJson = res.json();
pm.environment.set('currentAccessToken', responseJson.access_token)
var expiryDate = new Date();
expiryDate.setSeconds(expiryDate.getSeconds() + responseJson.expires_in);
pm.environment.set('accessTokenExpiry', expiryDate.getTime());
}
});
}
The above example is a Postman Pre-request script to fetch access_token, and the expire time of the token. I think this example will help you to solve the issue.
Please check the console of the postman
Open Postman Console by pressing Ctrl+Alt+C on Windows (Cmd + Alt+ C on mac)
Syntax error
When running your script I got the following error:
There was an error in evaluating the Pre-request Script: SyntaxError: Unexpected token ';'
It should be something like this in order to run correctly:
var expiresOn = pm.variables.get('ExpiresOn');
if (!expiresOn || new Date(expiresOn) <= new Date()) {
var clientId = '565v7677676vfdrd';
var apiToken = '6565fdvdrdfd';
var request = {
url: 'https://api.domain.io/api/user/session',
method: 'POST',
header: 'Content-Type:application/Json',
body: {
mode: 'application/json',
raw: clientId + apiToken
}
};
}
pm.sendRequest(request, function (err, res) {
if (res !== null) {
var json = res.json();
pm.environment.set('Access_Token', json.access_token)
var expiresOn = new Date(0);
expiresOn.setUTCSeconds(json.expires_on);
pm.environment.set('ExpiresOn', expiresOn);
}
});
Additional options
I used one of these two options to get the bearer token for my collection:
https://gist.github.com/bcnzer/073f0fc0b959928b0ca2b173230c0669#file-postman-pre-request-js
https://community.postman.com/t/how-to-automatically-set-a-bearer-token-for-your-postman-requests/10126/2
A bit modified Sebin Sunny's answer tested with JWT against Azure + resource (/audience).
In headers of request use Authorization {{$randomLoremSentence}}
const echoPostRequest = {
url: 'https://login.microsoftonline.com/{tenant}/oauth2/token',
method: 'POST',
body: {
mode: 'formdata',
formdata: [
{ key: 'grant_type', value: 'client_credentials' },
{ key: 'client_Id', value: '*******************************' },
{ key: 'client_secret', value: '*******************************' },
{ key: 'resource', value: '*******************************' }
]
}
};
var getToken = true;
var token = pm.globals.get('$randomLoremSentence') || '';
var exp = pm.globals.get('accessTokenExpiry');
var exps = new Date(exp);
if (token.indexOf('Bearer ') < 0) {
console.log('Token or expiry date are missing')
} else if (exp <= (new Date()).getTime()) {
console.log('Token is expired - ${exps}')
} else {
getToken = false;
console.log(`Token ${token.substr(0,10)}...${token.substr(-5)} and expiry ${exps} date are all good`);
}
if (getToken === true) {
pm.sendRequest(echoPostRequest, function (err, res) {
console.log(err ? err : res.json());
if (err === null) {
var responseJson = res.json();
var token = responseJson.access_token;
console.log(`Saving the token ${token.substr(0,5)}...${token.substr(-5)} and expiry ${exps} date`)
pm.globals.set('$randomLoremSentence', "Bearer " + token);
var expiryDate = new Date(responseJson.expires_on * 1000);
pm.globals.set('accessTokenExpiry', expiryDate.getTime());
}
});
}
//pm.globals.set('$randomLoremSentence', 0); // reset token 2 test

Using result of one function as a variable in another - node.js

I'm writing a node.js script to generate a GitHub installation access token. Here's what I've got:
const axios = require("axios");
var fs = require('fs');
var jwt = require("jsonwebtoken");
var gitInstallationAccessToken = {
genJWTToken: function(callback) {
var private_key = fs.readFileSync("/path/to/my/pemfile.pem");
const now = Math.round(Date.now() / 1000);
const payload = {
iat : now,
exp : now + (10 * 60),
iss : 7233
};
const token = jwt.sign(payload, private_key, { algorithm: 'RS256' })
callback(token);
},
genInstallationAccessToken: function(token, callback) {
var jwt = gitInstallationAccessToken.genJWTToken(function(token) {
return token;
});
console.log("JWT: ", jwt)
var instance = axios({
method: "post",
url: "https://api.github.com/installations/:installation_id/access_tokens",
headers: {
"Accept" : "application/vnd.github.machine-man-preview+json",
"Authorization" : `Bearer ${jwt}`
}
})
.then(function(response) {
console.log("Response: ",response.data);
callback(response);
})
.catch(function(error) {
console.warn("Unable to authenticate");
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
if (error.response) {
console.warn(`Status ${error.response.status}`);
console.warn(`${error.response.data.message}`);
}
});
}
}
module.exports = gitInstallationAccessToken;
gitInstallationAccessToken.genInstallationAccessToken(function(response) {
console.log("response: ", response)
});
My JWT token is getting generated by genJWTToken. I can see that if I add a console.log("Token: ", token) before the callback in genJWTToken.
I now need to use that token in genInstallationAccessToken but I'm clearly calling it wrong. As the following returns undefined:
var jwt = gitInstallationAccessToken.genJWTToken(function(token) {
return token;
});
console.log("JWT: ", jwt)
How do I fix this?
I think you should consider refactoring this and use chained promises it will be easier to understand and control..
Something like this:
function getToken() {
return new Promise(function(resolve, reject) {
resolve('token')
})
}
function chainPromise() {
var token
getToken().then((response) => {
token = response
console.log(token)
}).then(() => {
console.log('I am here and also see: ', token)
})
}
chainPromise()
You should then be able to track down the path of your token quite easily

Categories

Resources