Hi I am developing a web application with GDrive api in javascript.
In my page I can upload a file to the GDrive folder of the logged person.
What I want is that the file is public access to other user with a link to download the file.
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'title': fileData.name,
'mimeType': contentType
};
var body = {
'value': 'google account',
'type': 'anyone',
'role': 'reader'
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
if (!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
};
Related
I'm trying to make POST request on node.js to url, but always get ERROR 401 (Unauthorized).
const response = await fetch('url', {
method: 'POST',
mode: 'no-cors',
headers: {
"Content-Type": "text/html; charset=utf-8",
"Authorization": 'Basic ' + Buffer.from('username' + ":" + "password", 'base64').toString('base64')
},
body: ''
});
I'm tried to use btoa, however node.js does not support that...
headers.set('Authorization', 'Basic ' + btoa(username + ":" + password));
try this:
let loginData = "username" + ":" + "password";
let encodedData = new Buffer(loginData);
let base64data = encodedData.toString('base64');
I'm having an issue Updating a blobs name - I have done this no problem before but in this case I'm storing the blob in IndexedDB and based on certain conditions (save/saveas) it gets a name from Google Drive or you can add a new name.
Dom JS File
//Convert Text to Blob
let file = text;
fileName = "NewFileName";
let metadata = {
name: fileName, // Filename
mimeType: "application/pdf", // mimeType at Google Drive
};
let form = new FormData();
form.append(
"metadata",
new Blob([JSON.stringify(metadata)], { type: "application/json" })
);
form.append("file", file);
let textBlob = new Blob([file], {
'type': 'application/pdf',
});
Then My ServiceWorker Receives it and renames it then uploads it to google Drive
let blobPDF = request.result.text;
let blob = new Blob([blobPDF], {
type: "application/pdf"
});
let newBlob = new FormData();
console.log("Blob Name : " + saveas)
//Set New Name
newBlob.append("blob", blob, saveas);
fetch(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id",
{
method: "POST",
headers: new Headers({ Authorization: "Bearer " + accessToken }),
body: blob // Also tried newBlob var -> Got not a blob error
}
)
if I use the var newBlob it says it's not a blob and errors - then changed to "file" it still doesn't set name
One obvious mistake is that you're sending the blob itself as the body of your fetch request, not the newBlob form data object with the filename.
fetch("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id", {
method: "POST",
headers: new Headers({ Authorization: "Bearer " + accessToken }),
body: newBlob
// ^^^^
})
If that doesn't help, I'd try creating a File instead of a Blob:
let blob = new File([blobPDF], saveas, {
type: "application/pdf"
});
I want to upload a file to Google Drive but the file is uploaded without a filename. It upload as a 'Untitled' file. Please give me a solution if it works then I accept your answer Anyone here with a solution for this? Thanks in Advance. Here is my code.
userController.uploadToDrive = function(req, res){
token = req.body.token;
console.log(token);
var formData = new FormData();
console.log(token);
var fileMetadata = {
'name': 'all.vcf'
};
formData.append("data",fs.createReadStream('./all.vcf'), "all.vcf");
request({
headers: {
'Authorization': token,
'Content-Type' :'text/x-vcard',
},
resource: fileMetadata,
uri: 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart',
body: formData,
filename:'all.vcf',
method: 'POST'
}, function (err, resp, body) {
if(err){
console.log(err);
}else{
console.log('resp',body);
res.status(200).send()
fs.readdir('./contacts', function (err, files) {
var removefiles = function (file) {
fs.unlinkSync('./contacts/' + file)
}
files.forEach(function (file) {
removefiles(file)
})
})
}
});
}
It response like this:
resp {
"kind": "drive#file",
"id": "1tXu9Fc4sdi-yk8QGGvMJqSgxLXhuXNhQ",
"name": "Untitled",
"mimeType": "text/x-vcard"
}
I believe your goal and situation as follows.
You want to upload a file to Google Drive using multipart/form-data with Drive API.
Your access token can be used for uploading the file to Google Drive.
I think that in your case, the metadata and file content cannot be uploaded as multipart/form-data. By this, the file metadata cannot be reflected to the uploaded file. So in order to achieve this, I would like to propose the following modification.
Pattern 1:
In this pattern, const request = require("request") is used.
Modified script:
const fs = require("fs");
const request = require("request");
token = req.body.token;
fs.readFile("./all.vcf", function (err, content) {
if (err) {
console.error(err);
}
const metadata = {
name: "all.vcf",
mimeType: "text/x-vcard"
};
const boundary = "xxxxxxxxxx";
let data = "--" + boundary + "\r\n";
data += 'Content-Disposition: form-data; name="metadata"\r\n';
data += "Content-Type: application/json; charset=UTF-8\r\n\r\n";
data += JSON.stringify(metadata) + "\r\n";
data += "--" + boundary + "\r\n";
data += 'Content-Disposition: form-data; name="file"\r\n\r\n';
const payload = Buffer.concat([
Buffer.from(data, "utf8"),
Buffer.from(content, "binary"),
Buffer.from("\r\n--" + boundary + "--\r\n", "utf8"),
]);
request(
{
method: "POST",
url:
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
headers: {
Authorization: token,
"Content-Type": "multipart/form-data; boundary=" + boundary,
},
body: payload,
},
function (err, resp, body) {
if(err){
console.log(err);
}else{
console.log('resp',body);
res.status(200).send()
fs.readdir('./contacts', function (err, files) {
var removefiles = function (file) {
fs.unlinkSync('./contacts/' + file)
}
files.forEach(function (file) {
removefiles(file)
})
})
}
}
);
});
Pattern 2:
In this pattern, node fetch is used. In your script, new FormData() is used. So I thought that this pattern might be the direction you expect.
Modified script:
const FormData = require("form-data");
const fetch = require("node-fetch");
const fs = require("fs");
token = req.body.token;
var formData = new FormData();
var fileMetadata = {
name: "all.vcf",
mimeType: "text/x-vcard",
};
formData.append("metadata", JSON.stringify(fileMetadata), {
contentType: "application/json",
});
formData.append("data", fs.createReadStream("./all.vcf"), {
filename: "all.vcf",
});
fetch(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
{ method: "POST", body: formData, headers: { Authorization: token } }
)
.then((res) => res.json())
.then((json) => console.log(json));
Note:
In the case of uploadType=multipart, the maximum file size is 5 MB. Please be careful this. When you want to upload more large size, please use the resumable upload. Ref
References:
Upload file data
node-fetch
I am running into a problem with google drive rest api. I have a button and upon the user click, I get a blob excel file from my backend and upload the file to google drive. The file is being uploaded to the google drive, but when I opened it, it says '[object blob]'. The actual content isn't in the file. Here is my function for creating the file. I found this solution from here: Create File with Google Drive Api v3 (javascript)
var UploadExcelFile = function(name, data, callback){
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
const contentType = "application/vnd.google-apps.spreadsheet";
var metadata = {
'name': name,
'mimeType': contentType
};
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n\r\n' +
data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v3/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': 'multipart/related; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
if (!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
}```
```This is the response from the server:
Response {type: "basic", url:
"http://localhost:54878/home/generateexcel", redirected: false,
status:
200, ok: true, …}
body: ReadableStream
locked: true
__proto__: ReadableStream
bodyUsed: true
headers: Headers
__proto__: Headers
ok: true
redirected: false
status: 200
statusText: "OK"
type: "basic"
url: "http://localhost:54878/home/generateexcel"}
I am passing in the name of the file and the blob excel file from the backend like so:
fetch('/home/generateexcel', {
method: 'POST',
body: JSON.stringify(postData),
headers: {
"Content-Type": "application/json"
},
}).then(function (response) {
response.blob().then(function (result)
UploadExcelFile('newfile', result)
});
}).catch(function (err) {
// Error :(
});
You want to upload the downloaded xlsx file to Google Drive.
You have already confirmed that the xlsx file could be downloaded.
When a xlsx file is uploaded, you want to convert to Google Spreadsheet.
You can use Drive API and the access token for uploading files.
If my understanding is correct, how about this modification? In this modification, I used FormData() for creating the request body and used fetch() for requesting to Drive API. I think that there are several solutions for your situation. So please think of this as just one of them.
Modified script:
I modified UploadExcelFile(). Please modify as follows and try again.
function UploadExcelFile(name, data) {
var metadata = {
name: name,
mimeType: "application/vnd.google-apps.spreadsheet",
};
var form = new FormData();
form.append('metadata', new Blob([JSON.stringify(metadata)], {type: 'application/json'}));
form.append('file', data);
fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,name,kind', {
method: 'POST',
headers: new Headers({'Authorization': 'Bearer ' + gapi.auth.getToken().access_token}),
body: form
}).then((res) => {
return res.json();
}).then(function(val) {
console.log(val);
});
}
In my environment, I could confirm that this script worked. But if this didn't work in your environment, I apologize.
I am trying to integrate Google drive resumable file upload/update with my application. But when i update the file, file is updating in encoded format it is not taking the actual content. Encoded format is working for multiplepart uploadType but same content is not working for Resumable upload. Please find the below details
Step 1 : Start the resumable session
function uploadFile(fileData) {
var accessToken = 'ya29.nwI5Em6UnYGHvVzVx7lBk5tD-xzFl4_JG3_c-_t4FJ3owll_8i_rL5M17LFV6VlF7QE';
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'name': fileData.name,
'mimeType': contentType,
'Content-Type': contentType,
'Content-Length': fileData.size
};
var request = gapi.client.request({
'path' : 'upload/drive/v3/files',
'method' : 'POST',
'params' : {'uploadType':'resumable'},
'headers' : {
'X-Upload-Content-Type' : fileData.type,
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + accessToken,
},
'body' : metadata
});
request.execute(function(resp, raw_resp) {
var locationUrl = JSON.parse(raw_resp).gapiRequest.data.headers.location;
console.log(locationUrl);
uploadToLocationUrl(locationUrl, fileData);
});
}
Upto here it's fine I am getting Location Url and then calling a function to upload the file.
Step 2 : Resumable session initiation request
function uploadToLocationUrl(locationUrl, fileData)
{
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function (e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'name': fileData.name,
'mimeType': contentType,
'Content-Type': contentType,
'Content-Length': fileData.size
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var requestPost = gapi.client.request({
'path' : locationUrl,
'method' : 'PUT',
'headers' : {
'X-Upload-Content-Length' : fileData.size
},
'body' : multipartRequestBody
});
console.log(requestPost);
requestPost.execute(function(resp, raw_resp) {
console.log(resp);
});
}
}
Result : Updated file in google drive
---------314159265358979323846
Content-Type: application/json
{"name":"api.txt","mimeType":"text/plain"}
---------314159265358979323846
Content-Type: text/plain
Content-Transfer-Encoding: base64
MSkgTmVlZCBhbiBhcGkgd2hpY2ggd2lsbCByZXR1cm4gYWxsIGxlYWRzIGVtYWlsIGlkLg0KMikgTmVlZCBhbiBhcGkgdG8gY29udmVydCBtdWx0aXBsZSBjb250YWN0IGludG8gbGVhZC4NCjMpIE5lZWQgYW4gYXBpIGZvciBnb29nbGUgc2lnbiBpbi4vLyBkb24ndCBkaXNjdXNzIGFib3V0IHRoaXMgb25lIG5vdywgZmlyc3Qgd2Ugd2lsbCBkaXNjdXNzIGFib3V0IHRoaXMgQVBJLg==
---------314159265358979323846--
Sorry for the delayed answer,
you just need to change the uploadToLocationUrl function code
find below the updated code,
function uploadToLocationUrl(locationUrl, fileData,arrayBuffer)
{
var contentType = fileData.type || 'application/octet-stream';
var requestPost = gapi.client.request({
'path' : locationUrl,
'method' : 'PUT',
'headers' : {
'Content-Type': contentType,
"Content-Length": arrayBuffer.byteLength,
},
'data' : arrayBuffer
});
console.log(requestPost);
requestPost.execute(function(resp, raw_resp) {
console.log(resp);
});
}
you no need to send the metadata again, just byte array is fine.