Node Amazon

Como realizar upload no S3 com NestJS

Neste artigo vamos aprender o passo a passo de como realizar o upload de arquivos para a AWS S3 utilizando uma aplicação NestJS.

há 10 meses 1 semana

Formação Desenvolvedor Node Full-Stack
Conheça a formação em detalhes

No artigo anterior, aprendemos a criar uma aplicação que realiza o upload de arquivos localmente. No entanto, em uma aplicação real, esses arquivos devem ser acessados de forma remota. Dessa forma, podemos utilizar vários serviços disponíveis de armazenamento de arquivos estáticos. Neste artigo, vamos aprender a utilizar um dos principais serviços dessa categoria: o S3 da Amazon. Caso você não tenha nenhum conhecimento sobre o S3, sugiro a leitura do artigo “O que é AWS S3”, onde são explicadas com mais detalhes suas vantagens e limitações.

Node.js - Fundamentos
Curso Node.js - Fundamentos
Conhecer o curso

Criando conta na AWS S3

Agora vamos à prática. Precisamos fazer o cadastro no site https://aws.amazon.com/, vale ressaltar que logo na página inicial é possível obter informações sobre as ofertas e testes gratuitos. Para este artigo, iremos utilizar a oferta gratuita do S3.

Página inicial da AWS

Ao acessar o site, vamos criar uma conta clicando em “Crie uma conta da AWS” no canto superior direito. Na próxima página, você deverá fornecer um endereço de e-mail para a conta e o nome da conta da AWS.

Formulário de cadastro da AWS

Neste cadastro, a Amazon irá solicitar uma série de informações, incluindo a necessidade de um cartão de crédito, pois desta forma a Amazon faz a validação se é uma pessoa real que está se cadastrando. Entretanto, estaremos utilizando apenas a oferta gratuita e nada será cobrado do seu cartão, mas é sempre importante ficar atento a quaisquer cobranças que possam ocorrer e garantir que você esteja seguindo as limitações da oferta gratuita, pois essas regras podem mudar ao longo do tempo.

Após o cadastro, teremos acesso ao painel em que podemos pesquisar pelo nome do serviço na barra de pesquisa. Neste caso, pesquisaremos por S3 e, em seguida, clicaremos no resultado da busca.

Localizando o S3 no painel da AWS

Criando bucket

Agora devemos criar um bucket, é o termo utilizado pelo S3, basicamente é uma forma de definir e organizar os arquivos que serão armazenados no S3, podemos por exemplo ter vários buckets pra determinadas aplicações diferentes na mesma conta do S3.

Criando um bucket no S3

No próximo passo, vamos configurar este novo bucket da seguinte maneira:

  • Nome do bucket: neste campo, devemos inserir o nome do bucket, lembrando que ele deve ser único e exclusivo globalmente. Para este exemplo, vou criar com o nome “artigo-tw-s3”. No entanto, você deve criar outro nome, pois, como mencionado anteriormente, ele precisa ser exclusivo globalmente.
  • Região da AWS: neste campo, vamos selecionar a região mais próxima. Como sou de São Paulo, vou selecionar a opção “América do Sul (São Paulo) sa-east-1”.
  • Configurações de bloqueio de acesso publico deste bucket: Nessa opção, vamos permitir o acesso aos arquivos de forma pública. Para este exemplo, deixaremos os arquivos como públicos, pois poderão ser acessados por qualquer pessoa pela web, saliento que será público apenas para leitura. Também devemos selecionar o “checkbox” logo abaixo, na opção “Desativar bloqueio de todo acesso público…”.

cadastro de novo bucket

Nest.js - Fundamentos
Curso Nest.js - Fundamentos
Conhecer o curso

Opção de bloqueio de bucket público

As outras opções não precisam ser alteradas, vamos deixá-las como padrão. Enfim, o bucket será criado com sucesso:

Lista de buckets no painel do S3

Atualizando permissões do bucket

Precisamos atualizar as permissões do bucket para que qualquer pessoa possa acessar os arquivos, lembrando que neste exemplo os arquivos serão públicos. Para isso, vamos clicar no bucket ‘artigo-tw-s3’, em seguida, nas permissões, clicar em editar no item propriedades de objeto. Abrirá a seguinte tela, onde devemos habilitar as ACLs e selecionar a opção de proprietário do bucket preferida em propriedade do objeto:

Configurando permissões do bucket

Lembre-se de clicar em salvar as alterações.

Gerando chaves de acesso

Agora, devemos criar as chaves de acesso. Clique no menu com o nome da conta, localizado no canto superior direito, e em credenciais de segurança. Vamos em “Chaves de Acesso” e clique em criar chave de acesso. Aparecerá uma mensagem sobre chaves de acesso do usuário raiz. Selecione a caixa de seleção referente ao item “continuar a criar a chave de acesso?” e clique em criar chave de acesso:

Criando chaves de acesso Obs: lembre-se de guardar as chaves em um local seguro, não será possível ter acesso a chave de acesso secreta novamente.

Configurando aplicação NestJS para upload no S3

Agora, vamos configurar uma aplicação utilizando o NestJS para fazer o upload no S3. Para facilitar, vamos utilizar o projeto do artigo “como realizar upload de arquivos locais no NestJS”. A aplicação também pode ser encontrada neste repositório do GitHub.

Após configurar o projeto, vamos instalar o multer-s3 e o SDK da AWS:

npm install aws-sdk multer-s3 @types/multer-s3

Agora, no arquivo multer-config.ts, vamos fazer as alterações necessárias para salvar os arquivos no S3:

//multer-config.ts
import * as multerS3 from 'multer-s3';
import { S3Client } from '@aws-sdk/client-s3';
import * as path from 'path';
import { v4 as uuidv4 } from 'uuid';

const s3Config = new S3Client({
  region: 'sa-east-1', //região selecionada na criação do bucket
  credentials: {
    accessKeyId: 'AKIAXTVE2Q4BYHIUN6UY', //chave de acesso
    secretAccessKey: 'chave de acesso secreta', //chave de acesso secreta
  },
});

const multerConfig = {
  storage: multerS3({
    s3: s3Config,
    bucket: 'artigo-tw-s3',
    contentType: multerS3.AUTO_CONTENT_TYPE,
    acl: 'public-read',
    key: (req, file, cb) => {
      const fileName =
        path.parse(file.originalname).name.replace(/\s/g, '') + '-' + uuidv4();

      const extension = path.parse(file.originalname).ext;
      cb(null, `${fileName}${extension}`);
    },
  }),
};

export default multerConfig;

Obs: tome cuidado com a exposição das chaves de acesso, elas não devem ser expostas por questões de segurança. Essas chaves do exemplo já estão inativas.

Observe que, primeiramente, criamos uma constante chamada s3Config com os dados do S3, que são a região selecionada ao criar o bucket e as credenciais (chave de acesso e chave secreta).

Em seguida, atualizamos a constante multerConfig, trocando o storage para multerS3 e passando as propriedades necessárias para a comunicação com o S3:

  • S3: passamos as configurações através da constante s3Config;
  • bucket: o nome do bucket criado na conta do S3;
  • contentType: o content-type dos arquivos. No exemplo, utilizamos o AUTO_CONTENT_TYPE, onde o próprio multer identifica o content-type do arquivo.
  • acl: onde passamos as políticas de segurança e permissões do bucket. Neste caso, utilizamos o ‘public-read’, que significa que os dados podem ser lidos publicamente.
  • key: propriedade onde definimos o nome do arquivo.

Ótimo, agora precisamos atualizar o arquivo files.controller.ts:

//files.controller.ts
import {
  Controller,
  Post,
  UseInterceptors,
  UploadedFile,
  UploadedFiles,
} from '@nestjs/common';
import { FilesService } from './files.service';
import {
  FileFieldsInterceptor,
  FileInterceptor,
} from '@nestjs/platform-express';
import multerConfig from './multer-config';

@Controller('files')
export class FilesController {
  constructor(private readonly filesService: FilesService) {}

  @Post()
  @UseInterceptors(FileInterceptor('arquivo', multerConfig))
  uploadArquivo(@UploadedFile() file: Express.MulterS3.File) {
    console.log(file);
    return this.filesService.salvarDados(file);
  }

  @Post('varios')
  @UseInterceptors(FileFieldsInterceptor([{ name: 'arquivos' }], multerConfig))
  async uploadVariosArquivos(
    @UploadedFiles()
    files: Express.MulterS3.File[],
  ) {
    return await this.filesService.salvarVariosDados(files['arquivos']);
  }
}

Veja que atualizamos o tipo de file para Express.MulterS3.File, afinal, vamos utilizar as configurações do S3. Também eliminamos a utilização do objeto referente aos dados da requisição, já que não será mais necessário esses dados para criar a URL do arquivo. Essa URL será gerada pelo S3.

Nest.js - Templates com Handlebars
Curso Nest.js - Templates com Handlebars
Conhecer o curso

Por último, será necessário atualizar o arquivo files.service.ts, de acordo com as propriedades do S3:

import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { File } from './entities/file.entity';
import { Request } from 'express';

@Injectable()
export class FilesService {
  constructor(
    @InjectRepository(File)
    private fotoRepository: Repository<File>,
  ) {}

  async salvarDados(file: Express.MulterS3.File) {
    const arquivo = new File();
    arquivo.fileName = file.key;
    arquivo.contentLength = file.size;
    arquivo.contentType = file.mimetype;
    arquivo.url = file.location;

    return await this.fotoRepository.save(arquivo);
  }

  async salvarVariosDados(files: Express.MulterS3.File[]) {
    const arrayArquivos = files.map((file) => {
      const arquivo = new File();
      arquivo.fileName = file.key;
      arquivo.contentLength = file.size;
      arquivo.contentType = file.mimetype;
      arquivo.url = file.location;
      return arquivo;
    });

    return await this.fotoRepository.save(arrayArquivos);
  }
}

Atualizamos o nome do arquivo para file.key e a URL para file.location. Dessa forma, os dados serão salvos corretamente no nosso banco de dados. Com essas configurações atualizadas, podemos testar e enviar os arquivos para o upload no S3:

Testando rota de upload de arquivo único

Primeiramente, testamos a rota Files, que faz o upload de arquivos únicos, e obtivemos o retorno correto com os dados do arquivo e o código 201, ou seja, o upload foi efetuado com sucesso. Também podemos testar a rota files/varios, utilizada para fazer o upload de vários arquivos simultaneamente:

Testando rota de arquivos simultâneos

Neste caso, realizamos o teste com dois arquivos ao mesmo tempo, sendo uma imagem e um PDF, também com sucesso. Podemos verificar em nossa base de dados se as informações dos arquivos foram salvas:

Verificando dados salveos no banco de dados

Perfeito, os dados de ambos os arquivos foram salvos com sucesso.

Por fim, podemos visualizar os arquivos armazenados também no painel da AWS:

Lista de arquivos no S3

Conclusão

Neste artigo, aprendemos a fazer a integração de uma aplicação NestJS com o S3, um dos serviços de armazenamento de arquivos estáticos mais utilizados atualmente. Também utilizamos bibliotecas como o MulterS3 e o SDK da AWS, que auxiliam no desenvolvimento e nas configurações necessárias para essa integração.

Você pode consultar a aplicação de exemplo neste repositório.

Por fim, caso queira aprender mais sobre NestJS saiba que aqui na TreinaWeb temos o curso NestJS - Fundamentos que possui 02h07 de vídeos e um total de 18 exercícios. Conheça também nossos outros cursos de NestJS.

Veja quais são os tópicos abordados durante o curso de NestJS - Fundamentos:

  • Conhecendo a estrutura;
  • Utilizando Nest CLI
  • Entendendo Rotas, Controllers e Views;;
  • Conexão com banco de dados;
  • Usando TypeORM;
  • Template Engine.

Autor(a) do artigo

Wesley Gado
Wesley Gado

Formado em Análise e Desenvolvimento de Sistemas pelo Instituto Federal de São Paulo, atuou em projetos como desenvolvedor Front-End. Nas horas vagas grava Podcast e arrisca uns três acordes no violão.

Todos os artigos

Artigos relacionados Ver todos