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
- pegar o código base
- acessar pasta do projeto e instalar bibliotecas do projeto
- executar a api
- criar conta no imagekit.io e configurar acesso ao serviço
- incluir módulo nestjs para os novos endpoints
- codar o upload de arquivo para armazenamento na nuvem
- 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
- acessar imagekit.io e criar um conta gratuita;
- acessar imagekit.io conectado e criar uma chave privada;
- conectado e já com uma conta funcionando, acessar o dashboard
- no menu lateral, no meu caso direito, rolar e acessar
Developer options
- na página que abre, tem já pronto a Public key habilitada para copiar
- 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
- habilite Private key (keep confidential)
- codar no projeto o acesso a imagekit.io.
- criar e editar o arquivo
.env
na pasta raiz do projeto, como exemplo abaixo - criar e editar o arquivo
./src/configs/imagekit.config.ts
conforme arquivo abaixo - 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
- criar e editar o arquivo
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
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/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.