DEV Community

Leonardo Minora
Leonardo Minora

Posted on

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

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

Enter fullscreen mode Exit fullscreen mode

3. executar a api

[upload-api] $ npm run start:dev

Enter fullscreen mode Exit fullscreen mode
[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

Enter fullscreen mode Exit fullscreen mode

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/'
Enter fullscreen mode Exit fullscreen mode

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'),
});

Enter fullscreen mode Exit fullscreen mode

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 {}

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

5. incluir módulo nestjs para os novos endpoints

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

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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' };
++  }
++
}


Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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,
++    };
++  }
++}

Enter fullscreen mode Exit fullscreen mode

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

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

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);
  }
}

Enter fullscreen mode Exit fullscreen mode

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"
  }
}

Enter fullscreen mode Exit fullscreen mode

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

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

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

import {
  Controller,
++  Get,
++  Param,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { NuvemService } from './nuvem.service';
import {
++  ApiBadRequestResponse,
  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 this.nuvemService.upload(arquivo);
  }

++  @Get('nome/:arquivo_nome')
++  @ApiOperation({
++    summary: 'pegar um arquivo pelo seu nome que esta armazenado na nuvem',
++  })
++  @ApiResponse({ status: 201, description: 'Download de arquivo concluído.' })
++  @ApiBadRequestResponse({
++    status: 404,
++    description: 'ERRO arquivo não encontrado.',
++  })
++  downloadByNome(@Param('arquivo_nome') arquivo_nome: string) {
++    return { estado: 'ok' };
++  }
++
++  @Get('id/:arquivo_id')
++  @ApiOperation({
++    summary: 'pegar um arquivo pelo seu id que esta armazenado na nuvem',
++  })
++  @ApiResponse({ status: 201, description: 'Download de arquivo concluído.' })
++  @ApiBadRequestResponse({
++    status: 404,
++    description: 'ERRO arquivo não encontrado.',
++  })
++  downloadById(@Param('arquivo_id') arquivo_id: string) {
++    return { estado: 'ok' };
++  }
}

Enter fullscreen mode Exit fullscreen mode

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 2 endpoints Mapped {/armazenamento/:nome, GET} e Mapped {/nuvem/id/:arquivo_id, GET.

[16:42:11] File change detected. Starting incremental compilation...

[16:42:11] Found 0 errors. Watching for file changes.

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

Enter fullscreen mode Exit fullscreen mode

para ambas os endpoints, segue o exemplo de teste com a documentação swagger na figura abaixo e o resultado no console, também, abaixo.

{
  "estato": "ok"
}
Enter fullscreen mode Exit fullscreen mode

objetivo: recuperar informações do arquivo armazenado na nuvem imagekit.io.

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

--import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
++import {
++  HttpException,
++  HttpStatus,
++  Injectable,
++  NotFoundException,
++} 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 {
  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,
    };
  }
++
++  pegarPorNome(nome: string) {
++    const informacao = this.arquivos.filter((item) => item.nome === nome);
++    if (informacao.length === 0) {
++      throw new NotFoundException(`Arquivo (${nome}) não encontrado.`);
++    }
++    return informacao[0];
++  }
++
++  pegarPorID(id: string) {
++    const informacao = this.arquivos.filter((item) => item.id === id);
++    if (informacao.length === 0) {
++      throw new NotFoundException(`Arquivo (${id}) não encontrado.`);
++    }
++    return informacao[0];
++  }
}

Enter fullscreen mode Exit fullscreen mode

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

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

import {
  Controller,
  Get,
  Param,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { NuvemService } from './nuvem.service';
import {
  ApiBadRequestResponse,
  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 this.nuvemService.upload(arquivo);
  }

  @Get('nome/:arquivo_nome')
  @ApiOperation({
    summary: 'pegar um arquivo pelo seu nome que esta armazenado na nuvem',
  })
  @ApiResponse({ status: 201, description: 'Download de arquivo concluído.' })
  @ApiBadRequestResponse({
    status: 404,
    description: 'ERRO arquivo não encontrado.',
  })
  downloadByNome(@Param('arquivo_nome') arquivo_nome: string) {
--    return { estado: 'ok' };
++    return this.nuvemService.pegarPorNome(arquivo_nome);
  }

  @Get('id/:arquivo_id')
  @ApiOperation({
    summary: 'pegar um arquivo pelo seu id que esta armazenado na nuvem',
  })
  @ApiResponse({ status: 201, description: 'Download de arquivo concluído.' })
  @ApiBadRequestResponse({
    status: 404,
    description: 'ERRO arquivo não encontrado.',
  })
  downloadById(@Param('arquivo_id') arquivo_id: string) {
--    return { estado: 'ok' };
++    return this.nuvemService.pegarPorID(arquivo_id);
  }
}

Enter fullscreen mode Exit fullscreen mode

para a versão final dos endpoints, 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"
  }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)