Google Drive API: unsuccessful in updating the filename - node.js

I'm uploading a file to Drive and then trying to update the filename using the id. This is what I'm doing:
const updateFileName = await axios.patch(`https://www.googleapis.com/upload/drive/v3/files/${fileId}?updloadType=media`,
{'name':'MyFile.docx'},
{headers:
{'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'Authorization': `Bearer ${some_value}`,
},
},)
The problem is, instead of updating the filename, it updates the content of the file and replaces the content with {'name':'MyFile.docx'}. I can't figure out why it's replacing the actual content instead of the filename. The Drive v3 API for updating requires a name/originalName property in the request body, I tried with both. I've also tried replacing name with title. In all cases it overwrites the actual content in the file instead of changing the filename. Can someone please give me an idea about the workaround for this?

The problem is the ?updloadType=media which is telling Google you want to update the media content. Lose that bit, and you're off to the races. Content Type can probably be removed, but if you specify it, it should be application/json
and the URL should be https://www.googleapis.com/drive/v3/files/fileId

Related

Node native Fetch Upload Issue With Multer

I'm trying to migrate one of my systems from RequestJS to the new (currently experimental) fetch feature of Node 17.5+ but I'm having issues with the uploading of files, I'm hoping someone can assist.
At the receiving end I have Multer which is doing a simple upload.single('document') which always returns an empty object, so I'm fairly sure the way I'm sending the data is wrong.
In order to send the request, I'm doing the below (this is not the exact code, it's just to give an idea):
var requestOptions = {
headers: {'Content-Type': 'multipart/form-data'},
formData: {
document: {
value: _bufferData,
options: {
filename: _fileName,
contentType: _mimeType
}
}
}
};
Then I'm obviously sending the request using:
fetch('http://myurl.com/fileUpload', requestOptions).then(....);
I'm guessing new fetch API doesn't process the formData property the same way requestJS does. Does anyone know how I should be doing this?
Thanks.
Update: I've investigated further and the issue appears to be due to the content-disposition header missing the filename. I'm not sure how Multer creates this header but I assume its from the formdata, where the filename is clearly being passed in.

How to send form data with other additional data to a node server from vue

I am trying to send a number of data including an image to a node js server so that I can create a new document and store the image in the file system. I know that I should send a form data after appending the image to the backend and in the backend I should use multer package to read the form data and store the image. This I have implemented and works just fine.
The problem I am facing is that I have not been able to find a good way of sending form data alongside additional data, that are required for creating the new document in a single request. For that I first tried
something like this {...data, ...formData} but it didn't work. Then I tried appending all the additional data inside the form data itself.
formData.append("basicDetails", data);
formData.append("picture", picture);
const res = await axios.post(BASE_URL, formData, {
headers: {
'Authorization': `Bearer ${token}`
}
});
But now, since all the data is in form data, reading the data like req.body.basicDetails and trying the create a new document seems to not work. If I am not mistaken I need to use packages like multer to read form data. But is there a way to just use form data for picture and not for other data without making multiple requests?
I was researching a bit and I found this StackOverflow thread talking about formdata.
They were mentioning the headers, so add:
'Content-Type': 'multipart/form-data'
to your headers and try that.
Hope it works then :)

Downloading Binary File from OneDrive API Using Node/Axios

I am using the One Drive API to grab a file with a node application using the axios library.
I am simply trying to save the file to the local machine (node is running locally).
I use the One Drive API to get the download document link, which does not require authentication (with https://graph.microsoft.com/v1.0/me/drives/[location]/items/[id]).
Then I make this call with the download document link:
response = await axios.get(url);
I receive a JSON response, which includes, among other things, the content-type, content-length, content-disposition and a data element which is the contents of the file.
When I display the JSON response to the console, the data portion looks like this:
data: 'PK\u0003\u0004\u0014\u0000\u0006\u0000\b\u0000\u0000\u0000!\u...'
If the document is simply text, I can save it easily using:
fs.writeFileSync([path], response.data);
But if the file is binary, like a docx file, I cannot figure out how to write it properly. Every time I try it seems to have the wrong encoding. I tried different encodings.
How do I save the file properly based on the type of file retrieved.
Have you tried using an encoding option of fs.writeFileSync of explicitly null, signifying the data is binary?
fs.writeFileSync([path], response.data, {
encoding: null
});

Save an image file into a database with node/request/sequelize/mysql

I'm trying to save a remote image file into a database, but I'm having some issues with it since I've never done it before.
I need to download the image and pass it along (with node-request) with a few other properties to another node api that saves it into a mysql database (using sequelize). I've managed to get some data to save, but when I download it manually and try to open it, it's not really usable and no image shows up.
I've tried a few things: getting the image with node-request, converting it to a base64 string (read about that somewhere) and passing it along in a json payload, but that didn't work. Tried sending it as a multipart, but that didn't work either. Haven't worked with streams/buffers/multipart all that much before and never in node. I've tried looking into node-request pipes, but I couldn't really figure out how possibly apply them to this context.
Here's what I currently have (it's a part es6 class so there's no 'function' keywords; also, request is promisified):
function getImageData(imageUrl) {
return request({
url: imageUrl,
encoding: null,
json: false
});
}
function createEntry(entry) {
return getImageData(entry.image)
.then((imageData) => {
entry.image_src = imageData.toString('base64');
var requestObject = {
url: 'http://localhost:3000/api/entry',
method: 'post',
json: false,
formData: entry
};
return request(requestObject);
});
}
I'm almost 100% certain the problem is in this part because the api just takes what it gets and gives it to sequelize to put into the table, but I could be wrong. Image field is set as longblob.
I'm sure it's something simple once I figure it out, but so far I'm stumped.
This is not a direct answer to your question but it is rarely needed to actually store an image in the database. What is usually done is storing an image on storage like S3, a CDN like CloudFront or even just in a file system of a static file server, and then storing only the file name or some ID of the image in the actual database.
If there is any chance that you are going to serve those images to some clients then serving them from the database instead of a CDN or file system will be very inefficient. If you're not going to serve those images then there is still very little reason to actually put them in the database. It's not like you're going to query the database for specific contents of the image or sort the results on the particular serialization of an image format that you use.
The simplest thing you can do is save the images with a unique filename (either a random string, UUID or a key from your database) and keep the ID or filename in the database with other data that you need. If you need to serve it efficiently then consider using S3 or some CDN for that.

Podio file attached to item cannot be downloaded

I have an issue trying to download files attached to Podio items:
podio.request('get', '/file/{file_id}/raw').then(console.log);
The above program displays:
{}
This is a JSON stringified empty object (instead of raw file content).
Details:
The above file can be accessed with its URL when logged in
The above code is run after proper authentication
It actually works when using a file_id from an image field of the item, but not from a file attachment (pdf files in my case).
When using API endpoint /item/app/{app_id}/filter to get a list of items, the property file_count is set, but not files. I have to request /item/{item_id} individually to get the files property included in the response, not sure why.
Question: Do you know what is the issue, and how I can download raw attached files?
EDIT: aditionnal info
If I request a single file metadata using the folowing command:
podio.request('get', '/file/1234').then(console.log);
I get a file JSON object which includes many fields, but not the file content :
{
...
link: 'https://files.podio.com/1234',
file_id: 1234,
...
}
As stated in my comment to #stengaard, if I try to request the API for the above link, here is the response :
{ [PodioNotFoundError: [object Object]]
message:
{ error_parameters: {},
error_detail: null,
error_propagate: false,
request:
{ url: 'http://api.podio.com/1234',
query_string: '',
method: 'GET' },
error_description: 'No matching operation could be found. The path \'/1234\' was not found..',
error: 'not_found' },
status: 404,
url: 'https://api.podio.com:443/1234',
name: 'PodioNotFoundError' }
To use the GET /file/{file_id}/raw endpoint you need an API key with elevated trust levels.
Instead use GET /file/{file_id} endpoint. That contains a link attribute (a URL) you should follow to get the file content.
The link attribute will look like: https://files.podio.com/{file_id}. To fetch the file do https://files.podio.com/{file_id}?oauth_token={oauth_token}. Where the OAuth token is the same as the one used to GET /file/{file_id}. If you know the file ID (e.g. from a GET /item/{item_id} you can skip the GET /file/{file_id} and contact files.podio.com directly. (Note: You can also set the Authorization: OAuth2 {oauth_token} header in your HTTP request if you don't like passing the auth token in a URL paramter.)
For an example on how to use it see https://github.com/podio/podio-js/blob/master/lib/general.js#L11
Typically in the JS client, if you use podio as your Podio API object, the OAuth token would be located there:
podio.authObject.accessToken
So to get the raw content of the file in nodejs:
var url = 'https://files.podio.com/'+file_id+'?oauth_token='+podio.authObject.accessToken;
request(url, function (err, fileContent) {
// use fileContent here, write to a file, etc...
});
It seems your request has an error.
please try the below method and get raw file content from its response.
podio.request('get', '/file/{file_id}').then(console.log);
FYI, we couldn't get the files by filtering the items. we need to request /item/{item_id} individually to get the files property as you said.

Resources