AWS SDK для S3
Как устроена работа с объектным хранилищем S3 в @lowcode/api и как AWS SDK встроена в архитектуру платформы.
🎯 Зачем эта страница
Задача этой страницы — объяснить:
- что такое AWS SDK и какие задачи она решает;
- как настроить подключение к S3 или S3-совместимым хранилищам;
- как AWS SDK интегрирована в NestJS-модуль
@lowcode/api; - как правильно использовать StorageService для работы с файлами.
1. Что такое AWS SDK
AWS SDK для JavaScript — это официальная библиотека для работы с сервисами Amazon Web Services из Node.js-приложений.
В проекте используются два пакета:
- @aws-sdk/client-s3 — клиент для работы с S3 (загрузка, скачивание, удаление файлов).
- @aws-sdk/s3-request-presigner — генерация presigned URL для прямой загрузки/скачивания файлов клиентом.
Основные преимущества:
- модульная архитектура: подключаются только нужные сервисы (меньший размер бандла);
- строгая типизация: полная поддержка TypeScript;
- совместимость с S3-клонами: поддержка MinIO, Yandex Object Storage, и других S3-совместимых хранилищ через кастомный endpoint.
2. Минимальный пример AWS SDK в отрыве от проекта
2.1. Создание S3 клиента
import { S3Client } from '@aws-sdk/client-s3';
const s3Client = new S3Client({
region: 'us-east-1',
credentials: {
accessKeyId: 'YOUR_ACCESS_KEY',
secretAccessKey: 'YOUR_SECRET_KEY',
},
});
2.2. Генерация presigned URL для загрузки
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const command = new PutObjectCommand({
Bucket: 'my-bucket',
Key: 'path/to/file.png',
ContentType: 'image/png',
});
const uploadUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
console.log('Upload URL:', uploadUrl);
2.3. Генерация presigned URL для скачивания
import { GetObjectCommand } from '@aws-sdk/client-s3';
const command = new GetObjectCommand({
Bucket: 'my-bucket',
Key: 'path/to/file.png',
});
const downloadUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 });
console.log('Download URL:', downloadUrl);
2.4. Удаление файла
import { DeleteObjectCommand } from '@aws-sdk/client-s3';
const command = new DeleteObjectCommand({
Bucket: 'my-bucket',
Key: 'path/to/file.png',
});
await s3Client.send(command);
console.log('File deleted');
3. Где AWS SDK используется в @lowcode/api
В lowcode-платформе AWS SDK отвечает за работу с объектным хранилищем для модуля attachments.
Ключевые места:
- конфигурация: переменные окружения в
apps/api/.env; - сервис-обёртка:
StorageServiceвapps/api/src/modules/storage/storage.service.ts; - использование в сервисах:
AttachmentsServiceдля управления файлами.
Архитектурно это выглядит так:
Контроллер → AttachmentsService → StorageService → S3 (через AWS SDK)
Контроллеры не работают с S3 напрямую; они обращаются к AttachmentsService, который использует StorageService для работы с хранилищем.
4. Интеграция AWS SDK с NestJS
4.1. StorageService
В проекте используется обёртка над S3Client для удобной работы с хранилищем.
Полный пример:
// apps/api/src/modules/storage/storage.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { S3Client, DeleteObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
@Injectable()
export class StorageService {
private readonly s3Client: S3Client;
private readonly bucket: string;
private readonly urlExpiration: number;
constructor(private readonly config: ConfigService) {
const region = this.config.get<string>('S3_REGION', 'us-east-1');
const endpoint = this.config.get<string>('S3_ENDPOINT');
const accessKeyId = this.config.get<string>('S3_ACCESS_KEY_ID');
const secretAccessKey = this.config.get<string>('S3_SECRET_ACCESS_KEY');
this.bucket = this.config.get<string>('S3_BUCKET', 'lowcode-attachments');
this.urlExpiration = this.config.get<number>('S3_PRESIGNED_URL_EXPIRATION', 3600);
this.s3Client = new S3Client({
region,
...(endpoint && { endpoint }), // для совместимых с S3 сервисов
credentials: accessKeyId && secretAccessKey
? { accessKeyId, secretAccessKey }
: undefined,
});
}
async generateUploadUrl(key: string, contentType: string): Promise<string> {
const command = new PutObjectCommand({
Bucket: this.bucket,
Key: key,
ContentType: contentType,
});
return getSignedUrl(this.s3Client, command, { expiresIn: this.urlExpiration });
}
async generateDownloadUrl(key: string): Promise<string> {
const command = new GetObjectCommand({
Bucket: this.bucket,
Key: key,
});
return getSignedUrl(this.s3Client, command, { expiresIn: this.urlExpiration });
}
async deleteFile(key: string): Promise<void> {
const command = new DeleteObjectCommand({
Bucket: this.bucket,
Key: key,
});
await this.s3Client.send(command);
}
}
Этот сервис:
- инициализирует S3Client с настройками из конфигурации;
- поддерживает кастомный endpoint для S3-совместимых хранилищ;
- предоставляет методы для генерации presigned URL и удаления файлов.
4.2. StorageModule
Создаётся отдельный модуль, который экспортирует StorageService:
// apps/api/src/modules/storage/storage.module.ts
import { Global, Module } from '@nestjs/common';
import { StorageService } from './storage.service';
@Global()
@Module({
providers: [StorageService],
exports: [StorageService],
})
export class StorageModule {}
@Global() делает модуль доступным во всём приложении без явного импорта в каждый модуль.
4.3. Подключение к AppModule
В apps/api/src/app.module.ts модуль хранилища импортируется один раз:
@Module({
imports: [
StorageModule,
/* другие модули */
],
})
export class AppModule {}
После этого любой сервис может получать StorageService через DI.
5. Как сервисы используют StorageService
Пример использования в AttachmentsService:
// apps/api/src/modules/attachments/attachments.service.ts
import { Injectable } from '@nestjs/common';
import { StorageService } from '../storage/storage.service';
@Injectable()
export class AttachmentsService {
constructor(private readonly storage: StorageService) {}
async generateUploadUrl(clientId: string, projectId: string, filename: string, contentType: string) {
const storageKey = this.storage.generateStorageKey(clientId, projectId, filename);
const uploadUrl = await this.storage.generateUploadUrl(storageKey, contentType);
return { uploadUrl, storageKey };
}
async createS3(clientId: string, dto: CreateS3AttachmentDto) {
const url = await this.storage.generateDownloadUrl(dto.storageKey);
// ... создание записи в БД с url
}
async remove(clientId: string, id: string) {
const attachment = await this.ensureAttachment(clientId, id);
if (attachment.kind === 's3' && attachment.storageKey) {
await this.storage.deleteFile(attachment.storageKey);
}
// ... удаление записи из БД
}
}
Особенности подхода:
- Сервис получает
StorageServiceчерез конструктор. - Вся работа с S3 инкапсулирована в StorageService.
- AttachmentsService работает только с высокоуровневыми операциями.
6. Конфигурация окружения
6.1. Переменные окружения
Все настройки S3 задаются через .env файл:
# S3 / Object Storage настройки
S3_REGION=us-east-1
S3_ENDPOINT= # для S3-совместимых сервисов (MinIO, Yandex Object Storage)
S3_BUCKET=lowcode-attachments
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_PRESIGNED_URL_EXPIRATION=3600 # время жизни presigned URL в секундах
6.2. Работа с разными провайдерами
AWS S3:
S3_REGION=us-east-1
S3_ENDPOINT= # оставить пустым для AWS
S3_BUCKET=my-bucket
S3_ACCESS_KEY_ID=AKIA...
S3_SECRET_ACCESS_KEY=...
MinIO (локальная разработка):
S3_REGION=us-east-1
S3_ENDPOINT=http://localhost:9000
S3_BUCKET=lowcode-attachments
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
Yandex Object Storage:
S3_REGION=ru-central1
S3_ENDPOINT=https://storage.yandexcloud.net
S3_BUCKET=my-bucket
S3_ACCESS_KEY_ID=...
S3_SECRET_ACCESS_KEY=...
7. Где искать код, связанный с AWS SDK
| Компонент | Путь | Описание |
|---|---|---|
| StorageService | apps/api/src/modules/storage/storage.service.ts | Обёртка над S3Client |
| StorageModule | apps/api/src/modules/storage/storage.module.ts | Глобальный модуль с StorageService |
| Конфигурация | apps/api/.env | Переменные окружения для S3 |
| Использование в API | apps/api/src/modules/attachments/attachments.service.ts | Работа с файлами через StorageService |
8. Что нужно знать разработчику
Минимальный набор знаний, чтобы уверенно работать с AWS SDK в проекте:
- Где хранятся настройки S3 и как их конфигурировать для разных провайдеров.
- Как устроен
StorageServiceи какие методы он предоставляет. - Как генерировать presigned URL для загрузки/скачивания файлов.
- Как работает flow загрузки файла:
- Клиент запрашивает presigned URL через
POST /attachments/upload-url - Клиент загружает файл напрямую в S3 через PUT-запрос по полученному URL
- Клиент создаёт запись в БД через
POST /attachments/s3с storageKey
- Клиент запрашивает presigned URL через
Этого достаточно, чтобы:
- добавлять новую функциональность работы с файлами;
- переключаться между разными S3-провайдерами;
- понимать, как файлы проходят путь от клиента до хранилища и обратно.