Unable to upload file to Box using Node - node.js

I'm having a really tough time getting my files to upload to box using Node.js.
Every single time I attempt to, I get the following error:
Error: cannot POST /api/2.0/files/content (400)
Here is the relevant code. I've already double checked that this.options.auth contains the required tokens, etc. The parent_id folder is the root folder, so '0'. The filepath is a stream, which is totally fine.
request.post('https://upload.box.com/api/2.0/files/content')
.set('Authorization', this.options.auth)
.field('parent_id', folder)
.attach('filename', filepath)
.end(function (res) {
if (res.error) {
return callback('Error: '+res.error.message);
}
callback(null, res.body);
});
Any ideas?

HTTP status code 400 is used for a bad request. One thing to check is that the parameters you are supplying are all valid and that you haven't forgotten any required parameters. Looking at the Box API getting-started doc, it appears that what you are calling parent_id should be just parent. If it still doesn't work, check for other similar issues too, of course.

Related

Why can't I set two different states from the same response object?

I'm getting an S3 signed URL response back to my client from my NodeJS server which handles communication with S3. I need the signed URL to upload images directly to S3 from my front end, and I need the image URL to display it from the S3 bucket. However I can't seem to set two different states with the same response object without getting a 403(Forbidden) error. I can set one state just fine and use it, but as soon as I try and set two using the same response object, it doesn't like it.
403Error
useEffect(() => {
async function getURL() { try {
await axios.get("imageRouter/S3Url").then((response) => {
setImageUrl(response.data.url.split("?")[0]);
setSignedUrl(response.data.url);
});} catch (error) {
console.log(error);
}}
getURL();},
[selectedFile]);
selectedFile is not a dependency of useEffect, the two dependencies are: setImageUrl and setSignedUrl and you should cache them so they won't change every time the state changes (using React.memo).
You should check the signed URL that is returned, by default the expiration is 15 minutes IIRC, so if you generate it once and use it multiple times you should make sure that it's not expired and if so - regenerate it. This can be checked by looking at the Expires parameter which shows up as a query param on the signed-url. We can use: https://www.epochconverter.com/ to translate it to a timestamp in a more readable format

Vimeo API: Upload from a File Using a Form

I followed the docs for the vimeo node.js api to upload a file. It's quite simple and I have it working by running it directly in node, with the exception that it requires me to pass the full path of the file I want to upload. Code is here:
function uploadFile() {
let file = '/Users/full/path/to/file/bulls.mp4';
let video_id; //the eventual end URI of the uploaded video
lib.streamingUpload(file, function(error, body, status_code, headers) {
if (error) {
throw error;
}
lib.request(headers.location, function (error, body, status_code, headers) {
console.log(body);
video_id = body.uri;
//after it's done uploading, and the result is returned, update info
updateVideoInfo(video_id);
});
}, function(upload_size, file_size) {
console.log("You have uploaded " +
Math.round((upload_size/file_size) * 100) + "% of the video");
});
}
Now I want to integrate into a form generated in my react app, except that the result of evt.target.files[0] is not a full path, the result is this:
File {name: "bulls.mp4", lastModified: 1492637558000, lastModifiedDate: Wed Apr 19 2017 14:32:38 GMT-0700 (PDT), webkitRelativePath: "", size: 1359013595…}
Just for the sake of it, I piped that into my already working upload function and it didn't work for the reasons specified. Am I missing something? If not I just want to clarify what I actually have to do then. So now I'm looking at the official Vimeo guide and wanted to make sure that was the right road to go down. See: https://developer.vimeo.com/api/upload/videos
So if I'm reading it right, you do several requests to achieve the same goal?
1) Do a GET to https://api.vimeo.com/me to find out the remaining upload data they have.
2) Do a POST to https://api.vimeo.com/me/videos to get an upload ticket. Use type: streaming if I want a resumable upload such as those provided by the vimeo streamingUpload() function
3) Do a PUT to https://1234.cloud.vimeo.com/upload?ticket_id=abcdef124567890
4) Do a PUT to https://1234.cloud.vimeo.com/upload?ticket_id=abcdef124567890 but without file data and the header Content-Range: bytes */* anytime I want to check the bytes uploaded.
Sound right? Or can you simply use a form and I got it wrong somewhere. Let me know. Thanks.
There's some example code in this project that might be worth checking out: https://github.com/websemantics/vimeo-upload.
Your description is mostly correct for the streaming system, but I want to clarify the last two points.
3) In this step, you should make a PUT request to that url with a Content-Length header describing the full size of the file (as described here: https://developer.vimeo.com/api/upload/videos#upload-your-video)
4) In this step, the reason you are checking bytes uploaded is if you have completed the upload, or if your connection in the PUT request dies. We save as many bytes possible, and we will respond to the request in step 4. with how many bytes we received. This lets you resume step 3 where you left off instead of at the very beginning.
For stability we highly recommend the resumable uploader, but if you are looking for simplicity we do offer a simple POST uploader that uses an HTML form. The docs for that are here: https://developer.vimeo.com/api/upload/videos#simple-upload

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.

how to handle multiple conncurrency request in node.js

I am trying to upload multiple images at simultaneously. in server side i have to
create one unique folder for to keep that images .so how to make wait request until one request complete and send response to client. i have tried this one but when i send response i am getting this error Can't set headers after they are sent.so suggest me good solution . i am waiting for urs reply.
when i upload five images , in server side i have to check whether folder is already exist or not. if it is not exist i have to create new folder for that five images and then i have to check that folder reference is already exist or not in mongodb.if it is not exist i have to store that folder reference in mongodb.and then i have to send response to client. but here when i upload five image, five request is going to server so request is doing that terms before complete one request so same folder reference is storing and also it is creating five folder for five image.
function myMiddleware(req, res, next)
{
console.info("inside myMiddleware");
var handler = function()
{
console.info("middleware redundant. ActionDone, calling next");
next();
};
EventManager.once("finished",handler);
if (actionDone !== "working")
{
actionDone = "working";
function doneWaiting(){
// console.log("finished");
actionDone = "finished";
EventManager.emit( "finished" );
}
setTimeout(doneWaiting, 500);
}
I think that what you need here is implementing a lock on the function that checks/creates the folder and does the database check/create.
Take a look at this article to see an example

Google Translate API always returning "Required parameter: q" as error

I've been using Google Translate API for a while now, without any problems.
I recently pushed my app to my new server and even if it has been working perfectly on my local server, the same source code always gives me the "Required parameter: q" as error message.
I'm using NodeJS + ExpressJS + Request to send this request. Here's my test case:
var request = require('request');
request.post({
url: "https://www.googleapis.com/language/translate/v2",
headers: {"X-HTTP-Method-Override": "GET"},
form: {
key: /* My Google API server key */,
target: "en",
q: ["Mon premier essai", "Mon second essai"]
}
}, function(error, response, data) {
if (!error && response.statusCode == 200) {
console.log("everything works fine");
} else {
console.log("something went wrong")
}
});
Running on my local machine gives me "everything works fine", and running it on my server gives me "something went wrong". Digging more into it, I get the error message mentioned above.
As you can see, I'm trying to translate in one request two sentences. It's just a test case, but I really need to use this through POST request instead of doing two GET request.
I have no idea what this is happening, and I double checked my Google settings and I can't find something wrong there.
Also, I'm having no problem using Google Places APi with this same api key on my server.
I'm stuck. Anyone has any idea what's wrong here?
Well I finally found what was wrong: the new version of RequestJS doesn't work as the old one and my server was running 2.16 when my local machine was running 2.14.
The difference is the way the array is sent. I debugged and the old version was sending
key=my_api_key&target=en&q=Mon%20premier%20essai&q=Mon%20second%20essai
When the new version is sending
key=my_api_key&target=en&q[0]=Mon%20premier%20essai&q[1]=Mon%20second%20essai
So I just added 2.14.x instead of 2.x in my package.json file for now, hopefully it will get fixed soon — or maybe it's not a bug? I don't know.
This answer is a little late but to help people out there with this problem. The problem comes from the way the querystring module converts array parameters:
https://github.com/visionmedia/node-querystring
Its function qs.stringify converts fieldnames (q in the given example) that have an array value to the format:
q[0]=..q[1]=...
This is not a bug but an intended functionality. To overcome this problem without reverting to an old version of the request module you need to manually create your post by using the body option instead of the form option. Also you will need to manually add the content-type header with this method:
var request = require('request');
request.request({
url: "https://www.googleapis.com/language/translate/v2",
headers: {
"X-HTTP-Method-Override": "GET",
'content-type':'application/x-www-form-urlencoded; charset=utf-8'
},
body:'key=xxxx&target=en&q=q=Mon%20premier%20essai&q=Mon%20second%20essai'
}, function(error, response, data) {
if (!error && response.statusCode == 200) {
console.log("everything works fine");
} else {
console.log("something went wrong")
}
});
Obviously this is not as clean but you can easily create a utility function that creates the body string from the object the way you want it to.
things that pop into my head:
jquery file version on server and local PC are not the same
file encoding issues (UTF8 on PC ascii on server?)
have you tried testing it with chrome with Developer Tools open, then check "Network Tab" and verify exactly what is being sent to Google.
For me at least, when it works on one machine and not the other, it is usually due to the first 2 options.
Good Luck!

Resources