Stream S3 Object Data with AWS SDK v3
Explains how to use NodeJS streaming operations when working with S3 objects in the new AWS SDK v3.
I have recently worked on upgrading a small utility library I have developed from the AWS JavaScript SDK v2 to v3: @goldstack/utils-s3. This library simply provides a method to download a file from S3 to the local file system via the download
method:
export const download = async (params: {
key: string;
filePath: string;
s3: S3Client;
bucketName: string;
}): Promise<boolean> => {
}
I encountered an error after upgrading from the legacy S3
client to the new, recommend S3Client
. The latter is suggest to be used due to better support for tree shaking.
The error I encountered was .createReadStream()
method was no longer available on the Body
property returned in the response from the S3 client.
I previously created this stream to then pipe
the data of the object into a local object.
To get this working in the new v3 SDK library was a bit tricky. Essentially, the default S3Client
provided is designed to support both browser and Node-based environment. Since browser-based environments will not support NodeJs file streams, thus any methods related to that are missing in the API.
The work around for this is the following:
First, add the @smithy/types
package to your project.
npm install @smithy/types
Then add the following import to your source file.
import { NodeJsClient } from '@smithy/types';
Now after we have constructed the command, we cast the S3Client
to NodeJsClient<S3Client>
:
const s3Client = new S3Client();
const cmd = new GetObjectCommand({
Bucket: params.bucketName,
Key: params.key,
});
const res = await (s3Client as NodeJsClient<S3Client>).send(cmd);
In result, the the type for res.Body
will be SdkStream<IncomingMessage>
which offers all the methods we need for NodeJs streams, such as pipe
:
res.Body?.pipe(file);