NestJS – Armazenamento nas nuvens

Informações gerais

aula com endpoint para upload de arquivos com armazenamento em nuvem (cloud) para os alunos de programação orientada a serviços, do 4o ano de infoweb, do CNAT-IFRN
repositório de código
código final branch zip


This content originally appeared on DEV Community and was authored by Leonardo Minora

Informações gerais

  • aula com endpoint para upload de arquivos com armazenamento em nuvem (cloud) para os alunos de programação orientada a serviços, do 4o ano de infoweb, do CNAT-IFRN
  • repositório de código
  • código final branch zip

objetivo

  • criar 1 endpoint de upload de 1 arquivo com armazenamento em nuvem (cloud)
  • criar 1 endpoint de download de 1 arquivo que foi armazenado em nuvem (cloud)

notas de aula

sumário

  1. pegar o código base
  2. acessar pasta do projeto e instalar bibliotecas do projeto
  3. executar a api
  4. criar conta no imagekit.io e configurar acesso ao serviço
  5. incluir módulo nestjs para os novos endpoints
  6. codar o upload de arquivo para armazenamento na nuvem
  7. codar o "download" de arquivo armazenado na nuvem

1. pegar o código base

pode utilizar o seu próprio código, ou baixar o zip ou fazer o clone do repositório github com o código-fonte do projeto da nota de aula anterior.

lembrando que fazendo o clone do repositório github, precisará executar na pasta do projeto o comando git checkout -b 04-upload-cloud origin/04-upload-cloud.

2. acessar pasta do projeto e instalar bibliotecas do projeto

[upload-api] $ npm install imagekit-nestjs @nestjs/config

3. executar a api

[upload-api] $ npm run start:dev

[21:37:06] Starting compilation in watch mode...

[21:37:08] Found 0 errors. Watching for file changes.

[Nest] 237322  - 18/09/2024, 21:37:09     LOG [NestFactory] Starting Nest application...
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [InstanceLoader] AppModule dependencies initialized +17ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [InstanceLoader] NuvemModule dependencies initialized +0ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [InstanceLoader] UploadModule dependencies initialized +0ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RoutesResolver] AppController {/}: +19ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RoutesResolver] UploadController {/upload}: +1ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +7ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +1ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +0ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +1ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +0ms
[Nest] 237322  - 18/09/2024, 21:37:09     LOG [NestApplication] Nest application successfully started +2ms

4. criar conta no imagekit.io e configurar acesso ao serviço

  1. acessar imagekit.io e criar um conta gratuita;
  2. acessar imagekit.io conectado e criar uma chave privada;
    1. conectado e já com uma conta funcionando, acessar o dashboard
    2. no menu lateral, no meu caso direito, rolar e acessar Developer options
    3. na página que abre, tem já pronto a Public key habilitada para copiar
    4. nesta mesma página e logo ao lado de Public key, tem Private key (keep confidential) que vem desabilitada, caso sua conta seja criada com login de terceiros
    5. habilite Private key (keep confidential)
  3. codar no projeto o acesso a imagekit.io.
    1. criar e editar o arquivo .env na pasta raiz do projeto, como exemplo abaixo
    2. criar e editar o arquivo ./src/configs/imagekit.config.ts conforme arquivo abaixo
    3. editar o arquivo ./src/app.module.ts para configurar o acesso ao serviço do imagekit.io com as libs imagekit-nestjs e @nestjs/config, como arquivo abaixo

arquivo ./src/.env

  CLOUD_PUBLIC_KEY='COPIAR AQUI A SUA CHAVE PUBLICA'
  CLOUD_PRIVATE_KEY='COPIAR AQUI A SUA CHAVE PRIVADA'
  CLOUD_URL_ENDPOINT='https://ik.imagekit.io/SEU ImagekitID/'

arquivo ./src/configs/imagekit.config.ts

import { ConfigService } from '@nestjs/config';
import { ImageKitModuleOptions } from 'imagekit-nestjs';

export const ImageKitConfig = (
  configService: ConfigService,
): ImageKitModuleOptions => ({
  privateKey: configService.get('CLOUD_PRIVATE_KEY'),
  publicKey: configService.get('CLOUD_PUBLIC_KEY'),
  urlEndpoint: configService.get('CLOUD_URL_ENDPOINT'),
});

arquivo ./src/app.module.ts

import { Module } from '@nestjs/common';
++import { ConfigModule, ConfigService } from '@nestjs/config';
++import { ImageKitModule } from 'imagekit-nestjs';
++import { ImageKitConfig } from './configs/imagekit.config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UploadModule } from './upload/upload.module';
import { ArmazenamentoModule } from './armazenamento/armazenamento.module';

@Module({
--  imports: [UploadModule, ArmazenamentoModule],
++  imports: [
++    ConfigModule.forRoot(),
++    ImageKitModule.forRootAsync({
++      useFactory: ImageKitConfig,
++      inject: [ConfigService],
++      imports: [ConfigModule],
++      isGlobal: true,
++    }),
++    UploadModule,
++    ArmazenamentoModule,
++  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

após salvar os arquivos, o terminal de execução da API deve parecer com o console abaixo.

[13:56:12] File change detected. Starting incremental compilation...

[13:56:12] Found 0 errors. Watching for file changes.

[Nest] 273809  - 19/09/2024, 13:56:13     LOG [NestFactory] Starting Nest application...
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ConfigHostModule dependencies initialized +25ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ConfigModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] UploadModule dependencies initialized +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] NuvemModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ImageKitModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RoutesResolver] AppController {/}: +18ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RoutesResolver] UploadController {/upload}: +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [NestApplication] Nest application successfully started +3ms

5. incluir módulo nestjs para os novos endpoints

[upload-api] $ npx @nestjs/cli generate resource nuvem --no-spec

resultado da execução do comando de gerar recurso (module) nuvem.

[upload-api] $ npx @nestjs/cli g res nuvem --no-spec
? What transport layer do you use? REST API
? Would you like to generate CRUD entry points? No
CREATE src/nuvem/nuvem.controller.ts (210 bytes)
CREATE src/nuvem/nuvem.module.ts (248 bytes)
CREATE src/nuvem/nuvem.service.ts (89 bytes)
UPDATE src/app.module.ts (478 bytes)

resultado do terminal que esta com a API em execução.

[13:56:12] File change detected. Starting incremental compilation...

[13:56:12] Found 0 errors. Watching for file changes.

[Nest] 273809  - 19/09/2024, 13:56:13     LOG [NestFactory] Starting Nest application...
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ConfigHostModule dependencies initialized +25ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ConfigModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] UploadModule dependencies initialized +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] NuvemModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [InstanceLoader] ImageKitModule dependencies initialized +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RoutesResolver] AppController {/}: +18ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RoutesResolver] UploadController {/upload}: +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +1ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [RoutesResolver] NuvemController {/nuvem}: +0ms
[Nest] 273809  - 19/09/2024, 13:56:13     LOG [NestApplication] Nest application successfully started +3ms

6. codar o upload de arquivo para armazenamento na nuvem

objetivo: criar o endpoint para upload de 1 arquivo com documentação swagger.

modificar o arquivo src/nuvem/nuvem.controller.ts

--import { Controller } from '@nestjs/common';
--import { NuvemService } from './nuvem.service';
++import {
++  Controller,
++  Post,
++  UploadedFile,
++  UseInterceptors,
++} from '@nestjs/common';
++import { NuvemService } from './nuvem.service';
++import {
++  ApiBody,
++  ApiConsumes,
++  ApiOperation,
++  ApiResponse,
++  ApiTags,
++} from '@nestjs/swagger';
++import { FileInterceptor } from '@nestjs/platform-express';

@Controller('nuvem')
++@ApiTags('nuvem')
export class NuvemController {
  constructor(private readonly nuvemService: NuvemService) {}
++
++  @Post('upload')
++  @UseInterceptors(FileInterceptor('arquivo'))
++  @ApiConsumes('multipart/form-data')
++  @ApiBody({
++    schema: {
++      type: 'object',
++      properties: {
++        arquivo: {
++          type: 'string',
++          format: 'binary',
++        },
++      },
++    },
++  })
++  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
++  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
++  @ApiResponse({ status: 400, description: 'ERRO no upload do arquivo.' })
++  upload(@UploadedFile() arquivo: Express.Multer.File) {
++    return { estado: 'ok' };
++  }
++
}


após salvar o arquivo src/nuvem/nuvem.controller.ts, o terminal onde esta executando a API deve parecer com o console abaixo.
Note que foi adicionado mais um endpoint Mapped {/nuvem/upload, POST} route

[13:59:42] File change detected. Starting incremental compilation...

[13:59:42] Found 0 errors. Watching for file changes.

[Nest] 273999  - 19/09/2024, 13:59:42     LOG [NestFactory] Starting Nest application...
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] ConfigHostModule dependencies initialized +16ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] ConfigModule dependencies initialized +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] UploadModule dependencies initialized +1ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] NuvemModule dependencies initialized +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [InstanceLoader] ImageKitModule dependencies initialized +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RoutesResolver] AppController {/}: +20ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RouterExplorer] Mapped {/, GET} route +3ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RoutesResolver] UploadController {/upload}: +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +1ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +1ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RoutesResolver] NuvemController {/nuvem}: +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [RouterExplorer] Mapped {/nuvem/upload, POST} route +0ms
[Nest] 273999  - 19/09/2024, 13:59:42     LOG [NestApplication] Nest application successfully started +2ms

para essa versão do endpoint, o exemplo de teste com a documentação swagger na figura abaixo e o resultado no console, também, abaixo.

{
  "estato": "ok"
}

objetivo: armazenar o arquivo recebido na nuvem imagekit.io.

modificar o arquivo ./src/nuvem/nuvem.service.ts

import { Injectable } from '@nestjs/common';
++import { ImageKitService } from 'imagekit-nestjs';
++
++class ArquivoDto {
++  id: string;
++  nome: string;
++  tamanho: number;
++  mimetype: string;
++  encoding: string;
++  armazenamento: string;
++}

@Injectable()
--export class NuvemService {}
++export class NuvemService {
++  arquivos: ArquivoDto[] = [];
++
++  constructor(private readonly cloud: ImageKitService) {}
++
++  async upload(arquivo: Express.Multer.File) {
++    const resultado = await this.cloud.upload({
++      file: arquivo.buffer,
++      fileName: arquivo.originalname,
++    });
++
++    if (!resultado) {
++      throw new HttpException(
++        'Erro ao tentar armazenar arquivo na nuvem',
++        HttpStatus.NOT_ACCEPTABLE,
++      );
++    }
++
++    const informacao: ArquivoDto = {
++      id: resultado.fileId,
++      nome: arquivo.originalname,
++      encoding: arquivo.encoding,
++      mimetype: arquivo.mimetype,
++      tamanho: arquivo.size,
++      armazenamento: resultado.url,
++    };
++    this.arquivos.push(informacao);
++    return {
++      estado: 'ok',
++      data: informacao,
++    };
++  }
++}

objetivo: ligar o endpoint (controller) ao processamento de armazenamento (service).

modificar o arquivo FIXME

import {
  Controller,
  HttpStatus,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { NuvemService } from './nuvem.service';
import {
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('nuvem')
@ApiTags('nuvem')
export class NuvemController {
  constructor(private readonly nuvemService: NuvemService) {}

  @Post('upload')
  @UseInterceptors(FileInterceptor('arquivo'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        arquivo: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
--  @ApiResponse({ status: 400, description: 'ERRO no upload do arquivo.' })
++  @ApiResponse({
++    status: HttpStatus.NOT_ACCEPTABLE,
++    description: 'ERRO no upload do arquivo.',
++  })
  upload(@UploadedFile() arquivo: Express.Multer.File) {
--    return { estado: 'ok' };
++    return this.nuvemService.upload(arquivo);
  }
}

para a versão final do endpoint, o exemplo de teste com a documentação swagger na figura abaixo e o resultado no console, também, abaixo.

{
  "estado": "ok",
  "data": {
    "id": "66ec6724e375273f6095fca5",
    "nome": "diatinf.png",
    "encoding": "7bit",
    "mimetype": "image/png",
    "tamanho": 132200,
    "armazenamento": "https://ik.imagekit.io/minora/diatinf_nLtEXmRGb.png"
  }
}

7. codar o "download" de arquivo armazenado na nuvem


This content originally appeared on DEV Community and was authored by Leonardo Minora


Print Share Comment Cite Upload Translate Updates
APA

Leonardo Minora | Sciencx (2024-09-19T18:16:56+00:00) NestJS – Armazenamento nas nuvens. Retrieved from https://www.scien.cx/2024/09/19/nestjs-armazenamento-nas-nuvens/

MLA
" » NestJS – Armazenamento nas nuvens." Leonardo Minora | Sciencx - Thursday September 19, 2024, https://www.scien.cx/2024/09/19/nestjs-armazenamento-nas-nuvens/
HARVARD
Leonardo Minora | Sciencx Thursday September 19, 2024 » NestJS – Armazenamento nas nuvens., viewed ,<https://www.scien.cx/2024/09/19/nestjs-armazenamento-nas-nuvens/>
VANCOUVER
Leonardo Minora | Sciencx - » NestJS – Armazenamento nas nuvens. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/09/19/nestjs-armazenamento-nas-nuvens/
CHICAGO
" » NestJS – Armazenamento nas nuvens." Leonardo Minora | Sciencx - Accessed . https://www.scien.cx/2024/09/19/nestjs-armazenamento-nas-nuvens/
IEEE
" » NestJS – Armazenamento nas nuvens." Leonardo Minora | Sciencx [Online]. Available: https://www.scien.cx/2024/09/19/nestjs-armazenamento-nas-nuvens/. [Accessed: ]
rf:citation
» NestJS – Armazenamento nas nuvens | Leonardo Minora | Sciencx | https://www.scien.cx/2024/09/19/nestjs-armazenamento-nas-nuvens/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.