Multipart: Boundary not found - node.js

I am sending image selected from Expo Image Picker and other data in Form Data and passing it through Axios to node. But Unfortunately i am getting Error: Multipart: Boundary not found.
I need help.
Selected Image : "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FLevelNextClient-d47662dc-9f84-4299-a322-f00845340c43/ImagePicker/dcca0023-60e3-4c31-a16d-ce01e4ea758e.jpg"
const data = new FormData();
data.append('name', name)
data.append('email', email)
data.append('phone', phone)
data.append('image',
{
uri: image,
name: "UserProfile.jpg",
type: 'image/jpg'
});
const response = await axios.post(
`${ConfigData.SERVER_URL}/auth/updateProfile`,
data,
{headers: { 'Content-Type': 'multipart/form-data'},
});
router.post("/updateProfile", fileUpload.array("file"), async (req, res) => {
const busboy = Busboy({ headers: req.headers});
var saveLocation = '';
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
saveLocation = path.join(__dirname, 'uploads/videos' + filename);
file.pipe(fs.createWriteStream(saveTo));
});
busboy.on('finish', function() {
(async ()=>{
const user_id = req.body.id;
try {
const updateData=await userModel.updateOne(user_id,
{ name: req.body.name, email: req.body.email ,number: req.body.number,ProfileImageDestination : req.body.image},
);
res.writeHead(200, { 'Connection': 'close' });
res.end({ status: true ,updateData});
} catch (e) {
console.log(e);
res.writeHead(200, { 'Connection': 'close' });
res.end({ status: false, message: "Something Went Wrong" });
}
})()
});
return req.pipe(busboy);
});

Related

How do I send an image attachment via Email with Nodemailer in React?

I have asked this twice before two years ago and I still cannot get this to work. Let me explain.
How I want this to work is this:
User uploads some information in addition to an IMAGE file, NOT a text file.
I can easily send the text fields and receive them in an email.
I CANNOT receive the IMAGE file. It just appears blank with no file type or anything.
In the code, when the user hits the submit button, it is supposed to convert everything to a data form and upload that data to the backend.
However, while the text gets uploaded and sent, the file doesn't, so obviously I am missing something very fundamental here.
Do I actually need to upload the file to a physical file system like an HDD to then read the file on the server end? If so, how do I do that? Where do I save the file on the development side? How is this handled in production? Do I need a database for just one image file at a time? If I do need a database or some sort of physical storage, does that mean the flow would be to physically upload the file, read it, then delete it? Isn't that inefficient?
My last question can be seen here regarding the same current issue and I have yet to solve the problem: Why are my attachments not sending in Node.js?
What I want is to be able to see an image, NOT a blank attachment or a text file in my email attachment. I need an IMAGE file, a jpeg file specifically. How do I do this? What am I doing wrong? What buffer type am I supposed to use? The Nodemailer documentation has nothing that describes how to send an image, just all text files. Why won't this work? After two years on this I am at my wits end. Here again is my code, the relevant behavior is near the bottom of the server code:
FRONT END
import React, {Component} from "react";
import "./master.css";
import BuyHeader from "./images/buyBlocksHeader.png";
import LoginLabel from "./images/Label-Login.png";
import EmailLabel from "./images/Label-Email.png";
import ImageLabel from "./images/Label-Image.png";
import SubmitOff from "./images/Submit_Off.png";
import SubmitOn from "./images/Submit_On.png";
class Form extends Component {
constructor() {
super();
this.state = {
submitButton: SubmitOff,
_loginName: "",
_email: "",
_file: undefined,
};
}
baseURL = "http://localhost:8081/";
onLoginChange(event) {
this.setState({ _loginName: event.target.value })
}
onEmailChange(event) {
this.setState({ _email: event.target.value })
}
onFileChange(event) {
const file = event.target.value;
if (file){
this.setState({ _file: file});
}
console.log(file);
}
SendEmail = async(e) => {
e.preventDefault();
const formData = new FormData();
formData.append("loginName", this.state._loginName);
formData.append("email", this.state._email);
formData.append("file", this.state._file);
const response = await fetch(this.baseURL + "email", {
method: "POST",
mode: "cors",
body: formData,
});
const data = await response.json();
this.resetState();
console.log(data);
}
resetState() {
this.setState({_loginName: "", _email: "", _file: undefined});
this.props.handleFormState(false);
}
render () {
return (
<div>
<img src={BuyHeader} alt={""} />
<form onSubmit={this.SendEmail} encType="multipart/form-data">
<div>
<label htmlFor="loginName"><img src={LoginLabel} alt={""} /></label>
<input type="text" id="loginName" required value={this.state._loginName} onChange={this.onLoginChange.bind(this)}/>
</div>
<div>
<label htmlFor="email"><img src={EmailLabel} alt={""} /></label>
<input type="email" id="email" required value={this.state._email} onChange={this.onEmailChange.bind(this)} />
</div>
<div>
<label htmlFor="file"><img src={ImageLabel} alt={""} /></label>
<input type="file" id="file" required accept=".jpeg, .jpg" onChange={this.onFileChange.bind(this)} />
</div>
<div>
<button type="submit">
<img src={this.state.submitButton}
alt={""}
onMouseEnter={() => {
this.setState({ submitButton: SubmitOn });
}}
onMouseOut={() => {
this.setState({ submitButton: SubmitOff });
}}
/>
</button>
</div>
</form>
</div>
)
}
}
export default Form;
SERVER
const express = require("express")
const app = express();
const multer = require("multer");
const access = require("./config.json");
const {writeFile, readFileSync} = require("fs");
const accessPath = "./config.json";
require("dotenv").config();
const request = require("request");
const cors = require("cors");
const nodemailer = require("nodemailer");
const SMTPTransport = require("nodemailer/lib/smtp-transport");
app.use(cors({
origin: "*"
}));
app.use(express.json());
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header('Access-Control-Allow-Credentials', true);
next();
});
var file = access;
var PORT = file.port;
var server = app.listen(PORT, function() {
var port = server.address().port;
console.log("Back end listening at localhost:", port)
});
const fileData = readFileSync(accessPath, "utf8");
const jsonData = JSON.parse(fileData);
const upload = multer({
storage: multer.memoryStorage()
});
const directUpload = upload.fields([
{name: "loginName"},
{name: "email"},
{name: "file"}
]);;
const contactEmail = nodemailer.createTransport(new SMTPTransport({
name: "*****",
host: "*****",
port: ***,
secure: true,
auth: {
user: process.env.EMAIL,
pass: process.env.PASS,
},
}));
contactEmail.verify((error) => {
if (error) {
console.log(error);
} else {
console.log("Ready to send email request!");
}
});
var token = "";
var curToken = file.access_token;
var activeStreams = [];
var activeUser;
app.get('/', function(req, res) {
res.sendFile(__dirname + "/public/index.html");
});
/*Run this on initialization*/
function ValidateToken(currentToken) {
const options = {
url: process.env.VALIDATE_TOKEN,
json: true,
headers: {
"Client-ID": process.env.CLIENT_ID,
"Authorization": 'Bearer ' + currentToken,
}
};
request.get(options, (err, res, body) => {
if (err) {
return console.log(err);
}
console.log(res.statusCode);
if (res.statusCode !== 200) {
jsonData["access_token"] = "";
writeFile(accessPath, JSON.stringify(jsonData, null, 4), (error) => {
if (error) {
console.log("ERROR: File could not be written.", error);
}
console.log("File successfully written!");
})
const newFileData = readFileSync(accessPath, "utf8");
const data = JSON.parse(newFileData);
curToken = data.access_token;
}
})
}
ValidateToken(curToken);
function CheckToken(currentToken) {
if (currentToken === "") {
const GrabToken = (url, callback) => {
const options = {
url: process.env.GET_TOKEN,
json: true,
body: {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
grant_type: "client_credentials",
}
};
request.post(options, (err, res, body) => {
if (err) {
return console.log(err);
}
console.log(body);
callback(res);
})
};
GrabToken(process.env.GET_TOKEN, (res) => {
token = res.body.access_token;
const newFileData = readFileSync(accessPath, "utf8");
const data = JSON.parse(newFileData);
data["access_token"] = token;
writeFile(accessPath, JSON.stringify(data, null, 4), (error) => {
if (error) {
console.log("ERROR: File could not be written.", error);
}
console.log("File successfully written!");
})
console.log(token);
curToken = token;
return curToken;
})
};
console.log(curToken);
}
setTimeout(() => {
CheckToken(curToken)
}, 1000);
function FindStream(currentToken) {
const options = {
url: process.env.GET_STREAMER + file.user,
json: true,
headers: {
"Client-ID": process.env.CLIENT_ID,
"Authorization": 'Bearer ' + currentToken,
}
};
request.get(options, (err, res, body) => {
if (err) {
return console.log(err);
}
activeStreams = res.body.data.map(obj=>
obj.user_login);
console.log(activeStreams);
})
}
setTimeout(() => {
FindStream(curToken)
}, 1500)
/*End initialization*/
app.post('/streams', (req, res) => {
function ValidateToken(currentToken) {
const options = {
url: process.env.VALIDATE_TOKEN,
json: true,
headers: {
"Client-ID": process.env.CLIENT_ID,
"Authorization": 'Bearer ' + currentToken,
}
};
request.get(options, (err, res, body) => {
if (err) {
return console.log(err);
}
console.log(res.statusCode);
if (res.statusCode !== 200) {
jsonData["access_token"] = "";
writeFile(accessPath, JSON.stringify(jsonData, null, 4), (error) => {
if (error) {
console.log("ERROR: File could not be written.", error);
}
console.log("File successfully written!");
})
const newFileData = readFileSync(accessPath, "utf8");
const data = JSON.parse(newFileData);
curToken = data.access_token;
}
})
}
ValidateToken(curToken);
function CheckToken(currentToken) {
if (currentToken === "") {
const GrabToken = (url, callback) => {
const options = {
url: process.env.GET_TOKEN,
json: true,
body: {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
grant_type: "client_credentials",
}
};
request.post(options, (err, res, body) => {
if (err) {
return console.log(err);
}
console.log(body);
callback(res);
})
};
GrabToken(process.env.GET_TOKEN, (res) => {
token = res.body.access_token;
const newFileData = readFileSync(accessPath, "utf8");
const data = JSON.parse(newFileData);
data["access_token"] = token;
writeFile(accessPath, JSON.stringify(data, null, 4), (error) => {
if (error) {
console.log("ERROR: File could not be written.", error);
}
console.log("File successfully written!");
})
console.log(token);
curToken = token;
return curToken;
})
};
console.log(curToken);
}
setTimeout(() => {
CheckToken(curToken)
}, 1000);
function FindStream(currentToken) {
const options = {
url: process.env.GET_STREAMER + file.user,
json: true,
headers: {
"Client-ID": process.env.CLIENT_ID,
"Authorization": 'Bearer ' + currentToken,
}
};
request.get(options, (err, res, body) => {
if (err) {
return console.log(err);
}
activeStreams = res.body.data.map(obj=>
obj.user_login);
console.log(activeStreams);
})
}
setTimeout(() => {
FindStream(curToken)
}, 1500)
res.json(activeStreams);
})
app.get('/live', function(req, res) {
res.send(activeUser)
console.log("Received signal. " + activeUser);
});
app.post('/live', (req, res) => {
const {parcel} = req.body
activeUser = activeStreams.includes(parcel);
var userStatus = JSON.stringify(activeUser);
res.json(userStatus);
})
app.post('/email', directUpload, (req, res ) => {
const mailBody = {
from: req.file.email,
to: process.env.EMAIL,
subject: "The Block: Purchase Blocks Request",
html: `<p>Streamer Login Name: ${req.file.loginName}</p>
<p>Reply Email: ${req.file.email}</p>`,
attachments: [
{
__filename: "adImage.jpg", /*What should this be? The file name depends upon what the user uploaded*/
content: new Buffer.from(req.file.file, "base64"),
}
]
};
contactEmail.sendMail(mailBody, (error) => {
if (error) {
res.json({ status: "ERROR" });
} else {
res.json({ status: "Message sent!" });
}
});
})
I thank anyone who can provide a VERY DETAILED explanation of what I need to do, how to do it, what exactly I am doing wrong and why it is not working. I would love to finally be able to get this working. Thank you!!!

Axios POST request sending nothing with 'multipart/form-data' [React Native - Expo]

Scenario
Front end is basically a React Native (Expo) application where users can issue a report - this includes taking multiple photos and filling in some details.
Backend is just node.js, with Express & Multer.
Problem
I use Axios to send the images and form data through FormData(), however on the server side, req.body and req.files consist of nothing.
One thing here is that sending the SAME data through POSTMAN works COMPLETELY fine, the images were stored into S3 and the form details were stored in the database. It is through the app/emulator that does not work.
I've tried removing the "multipart/form-data" header and this is the output from console.log(req.body) (req.files show undefined):
{
_parts: [
[ 'userId', '1f400069-07d0-4277-a875-cbb2807750c5' ],
[
'location',
'some location'
],
[ 'description', 'Aaaaa' ],
[ 'report-images', [Object] ]
]
}
When I put the "multipart/form-data" header back this output didn't even bother showing up.
What I've Done
I've been searching for solutions for the past hours and none of them worked. Those solutions are:
Adding boundary behind the "multipart/form-data" header
Putting the type to "image/jpeg"
Trimming the file uri to "file://"
Yet none of them works
Here is my code:
React Native Frontend (Expo)
const submitReport = async () => {
setShowLoading(true);
// Validate details (location & images)
if (location === "") {
setShowLoading(false);
showToast(7002);
return;
}
if (images.length === 0) {
setShowLoading(false);
showToast(7004);
return;
}
try {
const formData = new FormData();
formData.append("userId", user.userId);
formData.append("location", location);
formData.append("description", description);
images.forEach(img => {
const trimmedURI = (Platform.OS === "android") ? img.uri : img.uri.replace("file://", "");
const fileName = trimmedURI.split("/").pop();
const media = {
name: fileName,
height: img.height,
width: img.width,
type: mime.getType(trimmedURI),
uri: trimmedURI
};
formData.append("report-images", media);
});
const response = await axios.post(`http://<my-ip-address>:3003/api/report/submit`, formData, { headers: { 'Content-Type': "application/x-www-form-urlencoded" } });
console.log(response)
setShowLoading(false);
}
catch (error) {
console.log(error);
setShowLoading(false);
showToast(9999);
}
};
Backend
// Multer-S3 Configuration
const upload = multer({
storage: multerS3({
s3: s3,
bucket: process.env.AWS_S3_BUCKET_NAME,
contentType: (req, file, callback) => {
callback(null, file.mimetype);
},
metadata: (req, file, callback) => {
callback(null, { fieldName: file.fieldname });
},
key: (req, file, callback) => {
callback(null, `${process.env.AWS_S3_REPORT_IMAGES_OBJECT_PATH}${req.body.userId}/${new Date().getTime().toString()}-${file.originalname}`)
}
}),
fileFilter: (req, file, callback) => {
// Check if file formats are valid
if (file.mimetype === "image/png" || file.mimetype === "image/jpg" || file.mimetype === "image/jpeg") {
callback(null, true);
}
else {
callback(null, false);
return callback(new Error("Image File Type Unsupported"));
}
},
});
router.post("/submit", upload.array("report-images", 3), async (req, res) => {
try {
// req -> FormData consisting of userId, location & description
// multer-s3 library will handle the uploading to S3 - no need to code here
// Details of files uploaded on S3 (Bucket, Key, etc.) will be displayed in req.files
// Analyze from Rekognition
//Add to Database code blablabla
if (result.success === true) {
res.status(200).send({ message: result.data });
}
else if (result.success === false) {
res.status(404).send({ error: ERROR_MESSAGE });
}
}
catch (error) {
console.log(error);
res.status(404).send({ error: ERROR_MESSAGE });
}
});
I'm unsure if this an Axios problem or some problem on my side.
This project is for my Final Year Project.
So after diving through search results in Google, I've found this StackOverflow post: react native post form data with object and file in it using axios
I took the answer provided by user_2738046 in my code and it worked! Combining with Ali's suggestion here is the final code that worked.
const FormData = global.FormData;
const formData = new FormData();
formData.append("userId", user.userId);
formData.append("location", location);
formData.append("description", description);
images.forEach(img => {
const trimmedURI = (Platform.OS === "android") ? img.uri : img.uri.replace("file://", "");
const fileName = trimmedURI.split("/").pop();
const media = {
name: fileName,
height: img.height,
width: img.width,
type: mime.getType(trimmedURI),
uri: trimmedURI
};
formData.append("report-images", media);
});
const response = await axios({
method: "POST",
url: `http://${<my-ip-address>}:3003/api/report/submit`,
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
},
transformRequest: (data, error) => {
return formData;
}
});
// If success, clear all text fields
if (response) {
showToast(7005);
setLocation("");
setImages([]);
setDescription("");
}
setShowLoading(false);
You need to change your image uploading code with this one, you also need to install mime npm package.
const formData = new FormData();
formData.append("userId", user.userId);
formData.append("location", location);
formData.append("description", description);
const formData = new FormData();
files = files || [];
if (files.length) {
for (let index = 0; index < files.length; index++) {
const filePayload = files[index];
const file = filePayload.value;
const localUri =
Platform.OS === "android" ?
file.uri :
file.uri.replace("file://", "");
const newImageUri = localUri;
const filename = newImageUri.split("/").pop();
const media = {
name: filename,
height: file?.height,
width: file?.width,
type: mime.getType(newImageUri),
uri: localUri,
};
formData.append(filePayload.name, media);
}
}
const response = await axios.post(`http://<my-ip-address>:3003/api/report/submit`, formData, {
headers: headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});

how to make or correct PDF data in response Nodejs

Getting response %PDF-1.4\n%����\n6 0 obj\n<</Type/XObject/Subtype/Image/Width 29/Height 29/Length 125/ColorSpace/DeviceGray/BitsPerComponent 1/Filter/CCITTFaxDecode/DecodeParms<</K -1/BlackIs1 true/Columns 29/Rows 29>>>>stream\n&����)�9_��~G?�A�G����?�q��(r�\b(�q�GA9�<?T\r���TD<D\�c��A�,Db������ ���\b����t\bdw�$�I/�\b.�"��G�
How to fix this response as readable pdf form please guide
const PDFDocument = require("pdfkit");
router.post("/get/PDF", (req, res) => {
axios({
method: "POST",
url: "http://143.155.55.11:8080/getPDF",
data: {
id: 1,
size: "A4",
},
headers: {
"Content-Type": "application/json",
},
})
.then(function (result) {
const doc = new PDFDocument();
let filename = "download";
// Stripping special characters
filename = encodeURIComponent(filename) + ".pdf";
// Setting response to 'attachment' (download).
// If you use 'inline' here it will automatically open the PDF
res.setHeader(
"Content-disposition",
'attachment; filename="' + filename + '"'
);
res.setHeader("Content-type", "application/pdf");
const content = encodeURIComponent(result.data);
doc.y = 300;
doc.text(content, 50, 50);
doc.pipe(res);
doc.end();
})
.catch(function (error) {
return res.status(500).json({
data: error,
status: "error",
message: "Something went wrong.",
});
});
});
router.post("/get/PDF", (req, res) => {
axios({
method: "POST",
url: "http://143.155.55.11:8080/getPDF",
data: {
id: 1,
size: "A4",
},
headers: {
"Content-Type": "application/json",
},
})
.then(function (result) {
const base64Str = Buffer.from(result.data).toString("base64");
let decodedBase64 = await base64topdf.base64Decode(
base64Str,
"download.pdf"
);
const fileContent = fs.readFileSync("download.pdf");
return res.status(200).json({
status: "success",
message: "Data send successfully.",
});
})
.catch(function (error) {
return res.status(500).json({
data: error,
status: "error",
message: "Something went wrong.",
});
});
});

Uploading blob/file in react-native, contents is empty

I am able to succesfully upload a blob with proper contents from my web browser, but when I do it from react-native, the upload file is empty. Here is the code:
async function doit() {
const data = new FormData();
data.append('str', 'strvalue');
data.append(
'f',
new File(['foo'], 'foo.txt', {type: 'text/plain'}),
);
await fetch('http://localhost:3002/upload', {
method: 'POST',
body: data
});
}
However doing this same code from react-native, it uploads, but the file is empty.
Here is the node.js server I am using to test this. Loading http://localhost:3002 gives you a button called "upload it". Clicking it does the upload from the web. Screenshots of results are below.
var multiparty = require('multiparty');
var http = require('http');
http
.createServer(function (req, res) {
if (req.url === '/upload' && req.method === 'POST') {
console.log('multipart here');
var form = new multiparty.Form();
form.parse(req, function (err, fields, files) {
console.log(require('util').inspect({ fields, files }, false, null, true));
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ bar: true }));
});
return;
}
console.log('here');
// show a file upload form
res.writeHead(200, { 'content-type': 'text/html' });
res.end(
`
<script>
async function doit() {
const data = new FormData();
data.append('str', 'strvalue');
data.append(
'f',
// new File([new Blob(['asdf'], {type : 'text/plain'})], 'filename.txt'),
new File(['foo', 'what', 'the', 'hell'], 'foo.txt', {type: 'text/plain'}),
);
const res = await fetch('http://localhost:3002/upload', {
method: 'POST',
body: data
});
console.log(JSON.stringify(res, null, 4));
}
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('b').addEventListener('click', doit, false)
}, false);
</script>
<button type="button" id="b">upload it</button>
`
);
})
.listen(3002);
From web browser we see the node server logs this, notice file size is 14.
However from react-native we see file size is 0:
I faced the same problem recently while posting an image from a react-native app to a server. However, I was able to make it work by appending the name and type of the file to the formData instance.
Here, the uri argument to uploadImageAsync is passed as a route parameter from the previous screen.
const postShoutHandler = async () => {
setShoutUploadStatus("Started Upload");
const response = await uploadImageAsync(route.params.captures);
const uploadResult = await response.json();
if (uploadResult === "Upload successful") {
setShoutUploadStatus("Success");
navigation.navigate("Home");
} else {
setShoutUploadStatus("Failed");
}
};
/* <--Upload image function --> */
const uploadImageAsync = (uri: string) => {
const apiUrl = "https://www.yourserver.com/image";
let uriParts = uri.split(".");
let fileType = uriParts[uriParts.length - 1];
let formData = new FormData();
formData.append("img", {
uri,
name: `photo.${fileType}`,
type: `image/${fileType}`,
});
formData.append("description", "HEY");
let options = {
method: "POST",
body: formData,
headers: {
Accept: "application/json",
"Content-Type": "multipart/form-data",
Authorization: "Bearer " + accessToken,
},
};
return fetch(apiUrl, options);
};
/* <--Upload image function --> */
Here is the Image configuration.
const photoData = await camera.takePictureAsync({
base64: true,
exif: false,
});

nodejs google drive api file download error with readablestream object

I'm trying to implement a function for downloading a file from the google drive using google drive api V3.
Below is my code.
service.files.get({
auth: this.oauth2Client,
fileId: fileId,
alt: 'media'
}, {responseType: "stream"}, function (err, response) {
console.log(response);
response.data
.on('end',() => {
console.log('Done');
})
.on('error', (err) => {
console.log('Error during download', err);
})
.on('data', d=> {
progress += d.length;
if (process.stdout.isTTY) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write('Download ${progress} bytes');
}
})
.pipe(dest);
})
When I run the code, I get this error.
response.data.on is not a function
Not just the on function, but the pipe function doesn't work either.
I already checked that response.data is the object of Readablestream.
Any ideas?
UPDATES
Below is the full code for GoogleDriveSyn class.
The getAllFilesInFolder function works fine.
const path = require('path')
const {google} = require('googleapis');
const fs = require('fs');
const service = google.drive('v3');
class GoogleDriveSyn {
constructor(auth) {
var apiKeys = JSON.parse(fs.readFileSync('config.json'));
this.oauth2Client = new google.auth.OAuth2(
apiKeys['CLIENT_ID'],
apiKeys['SECRET_ID'],
"http://localhost:8080"
);
this.oauth2Client.credentials = auth;
this.directory = localStorage.getItem('directory');
}
getAllFilesInFolder(folderId) {
var query = '"' + folderId + '"' + ' in parents and mimeType!="application/vnd.google-apps.folder"';
service.files.list({
auth: this.oauth2Client,
q: query,
pageSize: 50,
fields: 'nextPageToken, files(id, name, modifiedTime, kind, createdTime, thumbnailLink, mimeType, size, webContentLink)'
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
console.log(response);
return response
})
}
downloadFile(fileId, filePath, fileName) {
var fullPath = path.join(this.directory, filePath, fileName);
var dest = fs.createWriteStream(fullPath);
let progress = 0;
service.files.get({
auth: this.oauth2Client,
fileId: fileId,
alt: 'media'
}, {responseType: "stream"}, function (err, response) {
console.log(response);
response.data
.on('end',() => {
console.log('Done');
})
.on('error', (err) => {
console.log('Error during download', err);
})
.on('data', d=> {
progress += d.length;
if (process.stdout.isTTY) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write('Download ${progress} bytes');
}
})
.pipe(dest);
})
}
}
module.exports = GoogleDriveSyn;
Also, below is the log of response inside downloadFile function.
{config: {…}, data: ReadableStream, headers: {…}, status: 200, statusText: ""}
config: {url: "https://www.googleapis.com/drive/v3/files/1zcxy0wWsPuWINMY8FP_bjR4nrnj6t8eD?alt=media", method: "GET", responseType: "stream", headers: {…}, paramsSerializer: ƒ, …}
data: ReadableStream {locked: false}
headers: {alt-svc: "h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,…3"; ma=2592000,quic=":443"; ma=2592000; v="46,43"", cache-control: "private, max-age=0, must-revalidate", content-disposition: "attachment", content-length: "12", content-type: "text/plain", …}
status: 200
statusText: ""
__proto__: Object
I believe your goal and situation as follows.
You want to download a text file from the Google Drive.
Your script for authorizing works fine. So this.oauth2Client can be used for downloading the file.
Modification points:
In my environment, I confirmed that your script worked. But in your question, you say the error of response.data.on is not a function occurs. So in this modification, downloadFile was modified as follows.
At first, please confirm the version of googleapis for Node.js you are using. In this case, please use the latest version of googleapis for Node.js. In the current stage, the latest version is googleapis#55.0.0.
If you use the old one, I thought that the reason of your issue might be this.
In your script, 'Download ${progress} bytes' is not correct. In this case, please use it as the template literal. By this, the progress information can be seen.
Modified script:
downloadFile(fileId, filePath, fileName) {
var fullPath = path.join(this.directory, filePath, fileName);
var dest = fs.createWriteStream(fullPath);
let progress = 0;
return drive.files
.get(
{ auth: this.oauth2Client, fileId: fileId, alt: "media" },
{ responseType: "stream" }
)
.then((response) => {
return new Promise((resolve, reject) => {
response.data
.on("end", () => {
resolve("\nDone");
})
.on("error", (err) => {
reject(err);
})
.on("data", (d) => {
progress += d.length;
if (process.stdout.isTTY) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(`Download ${progress} bytes`);
}
})
.pipe(dest);
});
});
}
Reference:
Drive v3 API Samples
You can see the sample script at download.js.

Resources