I am using Twitter npm package to make a simple app that can upload gif or video to the platform. Getting 400 Bad Request error on the FINALIZE step. I can't understand why am I getting this error. I have structured my code as the example provided by the package and the Twitter docs. There is not much discussion about this error on stack overflow and in Twitter forums, they are saying that if a media file doesn't pass validation then this error is produced but they didn't specify the validations. If someone can explain why is it happening then that would be a great help.
let fs = require('fs')
let path = require('path')
const keys = require('./config')
const client = new Twitter(keys)
let mediaIdString = ''
let mediaId = 0
// reading file (GIF)
const gifFile = fs.readFileSync(path.join(__dirname, 'memes', 'gif1.gif'))
// getting file details
const gifFileStat = fs.statSync(path.join(__dirname, 'memes', 'gif1.gif'))
const gifSize = gifFileStat.size
const contentType = 'image/gif'
console.log(`gif size in bytes ==> ${gifSize}`)
// calling uploadMedia
uploadMedia().then((result) => {
console.log('UPLOAD SUCCESSFUL')
}).catch((err) => {
console.log(err)
})
function uploadMedia () {
// STEP 1 (INIT)
return client.post('media/upload', {
command: 'INIT',
total_bytes: gifSize,
media_type: contentType
}).then((response) => {
console.log(`INIT \t response ==> ${JSON.stringify(response)}`)
mediaIdString = response.media_id_string
mediaId = response.media_id
console.log(`mediaId ==> ${mediaId}`)
console.log(`media id string ==> ${mediaIdString}`)
// step 2 (APPEND)
return client.post('media/upload', {
command: 'APPEND',
media_id: mediaIdString,
media_data: gifFile,
segment_index: 0
})
}).then((response) => {
console.log(`APPEND \t response ==> ${JSON.stringify(response)}`)
// STEP 3 (STATUS)
return client.get('media/upload', {
command: 'STATUS',
media_id: mediaIdString
})
}).then((response) => {
console.log(`STATUS \t response ==> ${response}`)
// STEP 4 (FINALIZE)
return client.post('media/upload', {
command: 'FINALIZE',
media_id: mediaIdString
})
})
}
The first issue is that causing you to get Error: HTTP Error: 400 Bad Request
is the data you get by fs.readFileSync
is a raw binary file rather than base64-encoded file. API reference of Twitter states that:
media : The raw binary file content being uploaded. Cannot be used with
media_data
media_data : The base64-encoded file content being uploaded. Cannot be used with
media
So you should use media
parameter to pass the file instead of media_data
.
The second issue that your promise chain while trying to use chunked-upload approach is a little bit problematic and it should actually look like this:
client.post('media/upload', {
command: 'INIT',
total_bytes: gifSize,
media_type: contentType
}).then((response) => {
mediaIdString = response.media_id_string;
client.post('media/upload', {
command: 'APPEND',
media_id: mediaIdString,
media: gifFile,
segment_index: 0
}).then((response) => {
client.post('media/upload', {
command: 'FINALIZE',
media_id: mediaIdString,
}).then((response) => {
console.log(response);
console.log('UPLOAD SUCCESSFUL');
});
});
});
I think you tried to write a promise waterfall but I believe it does not work quite well in this case or if it works then it requires even more code to write and there is no performance difference at all.
Additionally, there is no mention of STATUS
command in twitter package's README.md so it seems like STATUS
is not supported by this library.