Skip to content

Instantly share code, notes, and snippets.

@VirtualPirate
Last active April 10, 2026 08:50
Show Gist options
  • Select an option

  • Save VirtualPirate/bd6949db7b5d0b898639dbe48e89e03c to your computer and use it in GitHub Desktop.

Select an option

Save VirtualPirate/bd6949db7b5d0b898639dbe48e89e03c to your computer and use it in GitHub Desktop.
NestJS AWS S3 service wrapper for uploading, deleting, fetching files, and generating signed URLs using AWS SDK v3.
import { PinoLogger } from "nestjs-pino";
import { Readable } from "stream";
import {
DeleteObjectCommand,
GetObjectCommand,
PutObjectCommand,
S3Client,
S3ClientConfig,
} from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { BaseService } from "./base.client";
@Injectable()
export class AWSService extends BaseService {
private readonly s3Client: S3Client;
private readonly region = "us-east-1";
private readonly bucketName = "";
constructor(private configService: ConfigService, private logger: PinoLogger) {
super();
this.logger.setContext(AWSService.name);
const s3Config: S3ClientConfig = {
region: this.region,
};
this.s3Client = new S3Client(s3Config);
this.bucketName = this.configService.getOrThrow("BUCKET_NAME");
}
init() {
// any methods here
}
/**
* This function take the following parameters and upload the file to amazon s3 bucket
*
* @param key This will be the path of the file inside the bucket
* @param content The file content you want to upload to s3
* @returns The url of the file that is uploaded
*/
async uploadFile(
key: string,
content: Buffer | Readable | string,
contentType: string,
): Promise<string> {
this.logger.info(`Uploading file to bucket: ${this.bucketName} in region: ${this.region}`);
const command = new PutObjectCommand({
Bucket: this.bucketName,
Key: key,
Body: content,
ContentType: contentType,
});
try {
await this.s3Client.send(command);
const objectUrl = `https://s3.${this.region}.amazonaws.com/${this.bucketName}/${key}`;
this.logger.info(`file uploaded to s3, ${objectUrl}`);
return objectUrl;
} catch (error) {
this.logger.error(`Error uploading file to S3: ${JSON.stringify(error)}`);
throw error;
}
}
async deleteS3Object(key: string) {
const command = new DeleteObjectCommand({
Bucket: this.bucketName,
Key: key,
});
try {
await this.s3Client.send(command);
} catch (error) {
this.logger.error(`Error deleting S3 object: ${key}`, error);
throw error;
}
}
async getSignedUrl(key: string, directDownload = false): Promise<string> {
const command = new GetObjectCommand({
Bucket: this.bucketName,
Key: key,
...(directDownload ? { ResponseContentType: "application/octet-stream" } : {}),
});
try {
const url = await getSignedUrl(this.s3Client, command, { expiresIn: 3600 }); // URL expires in 1 hour
this.logger.info(`Generated signed URL for key: ${key}`);
return url;
} catch (error) {
this.logger.error(`Error generating signed URL: ${error}`);
throw error;
}
}
async getObject(key: string) {
const command = new GetObjectCommand({
Bucket: this.bucketName,
Key: key,
});
try {
const data = await this.s3Client.send(command);
this.logger.info(`file fetched from s3, key: ${key}`);
// Convert the response stream to a Buffer
const stream = data.Body as Readable;
const chunks: Buffer[] = [];
for await (const chunk of stream) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
} catch (error) {
this.logger.error(error);
throw error;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment