Usecase: We have files in an S3 bucket with the respective information in our database. I would like to provide only an url for the frontend. Is this even possible?
At the moment it loads the whole object:
"descriptionFile": {
"id": 99,
"createdAt": "2020-07-23T11:58:59.510Z",
"updatedAt": "2020-07-23T11:58:59.510Z",
"s3Identifier": "asdfasdf-2we3123r99"
},
Goal: To only have an url in the response:
"descriptionFileUrl": "https://myapi.com/api/media/asdfasdf-2we3123r99"
These are my entities:
// category.entity.ts
@OneToOne(type => S3File)
@JoinColumn({ name: 'description_file_id' })
public descriptionFile: S3File;
// s3-file.entity.ts
@Column({ name: 's3_identifier', nullable: false })
public s3Identifier: string;
public get fullUrl() {
return 'https://' + this.s3Identifier;
}
Service function that load the data:
this.categoryRepository.find({
relations: [..., 'descriptionFile'],
});
I just stumpled upon my own question two years later. In the mean time I know that Presigned URLs are the best solution for this question.
The (imo) easiest way to use them in a node setup is the official package @aws-sdk/client-s3
: https://www.npmjs.com/package/@aws-sdk/client-s3. Note: this also works with minio. :)
Example:
// constructor of service class
constructor(...) {
this.s3Client = new S3Client({
credentials: {
accessKeyId: this.configService.s3AccessKey,
secretAccessKey: this.configService.s3SharedSecret,
},
forcePathStyle: true,
endpoint: this.configService.s3Host,
});
}
public getPresignedUrl(bucket: string, fileName: string): Promise<string> {
const signedUrlExpireSeconds = 60 * 60; // 1h
const command = new GetObjectCommand({
Bucket: bucket,
Key: fileName,
});
return getSignedUrl(this.s3Client, command, { expiresIn: signedUrlExpireSeconds });
}
Then you can use the getPresignedUrl
wherever you like in your project.