Reputation: 27962
I've seen various questions on SO about downloading files using Axios and uploading them to S3 but none that tie it all together and I'm getting confused with streams, blobs, multi-part forms etc. Here's my code so far.
Downloading the file.
const downloadResponse = await axios({
url: `https://example.com/test.jpg`,
method: 'GET',
responseType: 'stream' // Should this be blob, stream or arraybuffer?
})
Not sure what is contained within "downloadResponse.data" at this point, the typeof suggests it's an object, not a stream
Getting Signed response (this is done through Storyblok CMS not Amazon)
const signedResponse = await axios.post(`https://api.storyblok.com/v1/spaces/xxx/assets`, {
filename: 'test.jpg',
}, {
headers: {'Authorization': 'xxxxx'}
})
Creating the form data using form-data package
let form = new FormData()
for (var key in signedResponse.fields) {
form.append(key, signedResponse.fields[key])
}
try {
form.append('file', fs.createReadStream(downloadResponse.data))
} catch (error) {
console.log("Error Creating Data", error)
}
Uploading to S3
try {
const uploadResponse = await axios({
method: 'post',
url: signedResponse .data.post_url,
data: form.getBuffer(),
headers: form.getHeaders()
})
} catch (error) {
console.log("Error Uploading", error)
}
At the moment this is causing the following error when creating the stream..
Error Creating Data TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type object.
I have tried taking the data directly from the first request and not using fs.createReadStream() on it as it should already be a stream but that gives the same error.
I have also tried returning an arraybuffer from the first request and using Buffer.from() and then attaching the buffer but that didn't work either, I think Amazon gave me a 400 error from that so I'm lost.
Any help would be really appreciated.
Upvotes: 6
Views: 9878
Reputation: 7896
This code uses v3 version of AWS JS SDK. Using Node v16 (ES16 Module)
// Ref: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/index.html
import { S3Client } from '@aws-sdk/client-s3';
// Constants
const accessKeyId = process.env.AWS_ACCESS_KEY
const secretAccessKey = process.env.AWS_SECRET_KEY
const awsRegion = 'ap-south-1';
export const awsBucket = process.env.AWS_BUCKET;
export const S3 = new S3Client({
credentials: {
accessKeyId,
secretAccessKey,
},
region: awsRegion,
});
responseType: 'arraybuffer'
const resp = await axios.get('https://domain/image/imagename.png', {
decompress: false,
// Ref: https://stackoverflow.com/a/61621094/4050261
responseType: 'arraybuffer',
})
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { awsBucket, S3 } from '../lib/aws.js'; // Defined in Point 1 above
await S3.send(
new PutObjectCommand({
Bucket: awsBucket,
Key: `foldername/filename`,
Body: resp.data,
})
)
Upvotes: 13