Informações gerais
- aula com endpoint para upload de arquivos 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 03-upload-arquivos-multiplos zip
objetivo
- criar 1 endpoint para API de upload de múltiplos arquivos
notas de aula
sumário
- pegar o código do projeto anterior
- executar a API
- criar e configurar 1 endpoint para receber vários arquivos
- criar método no serviço para retornar as informações dos arquivos
para receber vários arquivos, o nestjs disponibiliza os seguintes interceptors:
-
FilesInterceptor
- identifica um array de arquivos com o mesmo nome de campo do formulário; -
FileFieldsInterceptor
- -
AnyFilesInterceptor
-
1. pegar o código do projeto anterior
a nota de aula anterior é NestJS - Upload de 1 arquivo que criou um projeto javascript para uma API Rest usando nestjs e typescript.
pode utilizar o seu próprio código, ou baixar o zip ou fazer o clone do repositório github.
2. Executar a API
lembre de acessar a pasta do projeto!!!
antes de executar a api, lembrar de instalar as bibliotecas do projeto com o comando npm i
.
lançar a api em modo desenvolvimento executando o comando npm
com a opção run
para executar o script start:dev
.
[upload-api] $ npm run start:dev
a execução deverá produzir um resultado parecido com o console abaixo.
[11:58:35] Starting compilation in watch mode... [11:58:37] Found 0 errors. Watching for file changes. [Nest] 12346 - 15/09/2024, 11:58:38 LOG [NestFactory] Starting Nest application... [Nest] 12346 - 15/09/2024, 11:58:38 LOG [InstanceLoader] AppModule dependencies initialized +14ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [InstanceLoader] UploadModule dependencies initialized +1ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RoutesResolver] AppController {/}: +15ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RouterExplorer] Mapped {/, GET} route +3ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RoutesResolver] UploadController {/upload}: +0ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +2ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [NestApplication] Nest application successfully started +4ms
3. criar e configurar 1 endpoint para receber vários arquivos
adicionar um endpoint no controller src/upload/upload.controller.ts
, atualizando as importações, conforme código (diff) abaixo.
import { Controller, Post, UploadedFile, ++ UploadedFiles, UseInterceptors, } from '@nestjs/common'; --import { FileInterceptor } from '@nestjs/platform-express'; ++import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express'; import { ++ ApiBadRequestResponse, ApiBody, ApiConsumes, ApiOperation, ApiResponse, ApiTags, } from '@nestjs/swagger'; import { UploadService } from './upload.service'; @Controller('upload') @ApiTags('upload') export class UploadController { constructor(private readonly uploadService: UploadService) {} @Post('exemplo-simples') @UseInterceptors(FileInterceptor('arquivo')) @ApiConsumes('multipart/form-data') @ApiBody({ schema: { type: 'object', properties: { arquivo: { type: 'string', format: 'binary', }, }, }, }) @ApiOperation({ summary: 'Exemplo de upload de 1 arquivo qualquer' }) @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' }) @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' }) uploadArquivoSimples(@UploadedFile() arq: Express.Multer.File) { console.log(arq); return this.uploadService.responderInformacaoArquivo(arq); } ++ @Post('arquivos') ++ @UseInterceptors(FilesInterceptor('arquivos')) ++ @ApiConsumes('multipart/form-data') ++ @ApiBody({ ++ schema: { ++ type: 'object', ++ properties: { ++ arquivos: { ++ type: 'array', ++ items: { ++ type: 'string', ++ format: 'binary', ++ }, ++ }, ++ }, ++ }, ++ }) ++ @ApiResponse({ ++ status: 201, ++ description: 'Arquivo(s) enviado(s) com sucesso.', ++ }) ++ @ApiBadRequestResponse({ ++ status: 400, ++ description: 'Erro no envio de arquivos.', ++ }) ++ uploadArquivos(@UploadedFiles() arquivos: Array<Express.Multer.File>) { ++ return { ++ estado: 'ok', ++ data: { ++ quantidade: arquivos?.length, ++ }, ++ }; ++ } }
foi adicionado nas importações o interceptor FilesInterceptor
e o decorator UploadedFiles
responsáveis por interceptar e extrair vários arquivos em uma array nomeada como arquivos
no formulário.
o decorator @Post
configura o verdo POST
e o path arquivos
do endpoint.
enquanto o decorator @UseInterceptors
configura o uso do FilesInterceptor
para interceptar a requisitação HTTTP(S) a procura da variável arquivos
dentro do formulário no corpo da mensagem.
as próximas linhas contém os decorators @Api
(ApiConsumes
, ApiBody
, ApiResponse
, e ApiBadRequestResponse
) para configurar a documentação do swagger.
a próxima linha, uploadArquivos(@UploadedFiles() arquivos: Array<Express.Multer.File>)
especifica o método uploadArquivos
.
este método tem como parâmetro a variável arquivos
que irá receber um array contendo itens cada tipados com Express.Multer.File
.
o parâmetro arquivos
também esta decorado com UploadedFiles
que é responsável por extrair o array de arquivos da mensagem HTTP.
ao salvar, a api será relançada e o terminal onde ela esta sendo executada deverá ficar como o console abaixo.
[11:58:35] Starting compilation in watch mode... [11:58:37] Found 0 errors. Watching for file changes. [Nest] 12346 - 15/09/2024, 11:58:38 LOG [NestFactory] Starting Nest application... [Nest] 12346 - 15/09/2024, 11:58:38 LOG [InstanceLoader] AppModule dependencies initialized +14ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [InstanceLoader] UploadModule dependencies initialized +1ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RoutesResolver] AppController {/}: +15ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RouterExplorer] Mapped {/, GET} route +3ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RoutesResolver] UploadController {/upload}: +0ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +2ms [Nest] 12346 - 15/09/2024, 11:58:38 LOG [NestApplication] Nest application successfully started +4ms
para testar, use a documentação da api acessando o endereço http://localhost:3000/docs/
clique no botão Try it out
, escolher alguns arquivos, e clicar em Execute
.
a operação deve estar semelhante com a figura abaixo e o resultado após a execução com o json abaixo da figura.
{ "estado": "ok", "data": { "quantidade": 3 } }
4. criar método no serviço para retornar as informações dos arquivos
no arquivo src/upload/upload.service.ts
crie o método responderInformacoesArquivos(arquivos: Array<Express.Multer.File>)
e coloque a implementação conforme arquivo (diff) abaixo.
import { Injectable } from '@nestjs/common'; @Injectable() export class UploadService { responderInformacaoArquivo(arquivo: Express.Multer.File) { return { estado: 'ok', dados: { nome: arquivo.originalname, tamanho: arquivo.size, mimetype: arquivo.mimetype, encode: arquivo.encoding, }, }; } ++ ++ responderInformacoesArquivos(arquivos: Array<Express.Multer.File>) { ++ const informacoes = arquivos.map((arquivo) => { ++ return { ++ nome: arquivo.originalname, ++ tamanho: arquivo.size, ++ mimetype: arquivo.mimetype, ++ encode: arquivo.encoding, ++ }; ++ }); ++ return { ++ estado: 'ok', ++ dados: { ++ quantidade: arquivos?.length, ++ arquivos: informacoes, ++ }, ++ }; ++ } }
após a modificação do service
terá de modificar o controller
no arquivo src/upload/upload.controller.ts
conforme arquivo abaixo para chamar o método responderInformacoesArquivos
.
import { Controller, Post, UploadedFile, UploadedFiles, UseInterceptors, } from '@nestjs/common'; import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express'; import { ApiBadRequestResponse, ApiBody, ApiConsumes, ApiOperation, ApiResponse, ApiTags, } from '@nestjs/swagger'; import { UploadService } from './upload.service'; @Controller('upload') @ApiTags('upload') export class UploadController { constructor(private readonly uploadService: UploadService) {} @Post('exemplo-simples') @UseInterceptors(FileInterceptor('arquivo')) @ApiConsumes('multipart/form-data') @ApiBody({ schema: { type: 'object', properties: { arquivo: { type: 'string', format: 'binary', }, }, }, }) @ApiOperation({ summary: 'Exemplo de upload de 1 arquivo qualquer' }) @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' }) @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' }) uploadArquivoSimples(@UploadedFile() arq: Express.Multer.File) { console.log(arq); return this.uploadService.responderInformacaoArquivo(arq); } @Post('arquivos') @ApiConsumes('multipart/form-data') @ApiBody({ schema: { type: 'object', properties: { arquivos: { type: 'array', items: { type: 'string', format: 'binary', }, }, }, }, }) @ApiResponse({ status: 201, description: 'Arquivo(s) enviado(s) com sucesso.', }) @ApiBadRequestResponse({ status: 400, description: 'Erro no envio de arquivos.', }) @UseInterceptors(FilesInterceptor('arquivos')) uploadArquivos(@UploadedFiles() arquivos: Array<Express.Multer.File>) { -- return { -- estado: 'ok', -- dados: { -- quantidade: arquivos?.length, -- arquivos: informacoes, -- }, -- }; ++ return this.uploadService.responderInformacoesArquivos(arquivos); } }
para testar, pode usar novamente a documentação da API conforme a figura anterior.
o resultado agora será parecido conforme o json
abaixo.
{ "estado": "ok", "dados": { "quantidade": 3, "arquivos": [ { "nome": "README.md", "tamanho": 1373, "mimetype": "text/markdown", "encode": "7bit" }, { "nome": "package.json", "tamanho": 2020, "mimetype": "application/json", "encode": "7bit" }, { "nome": "Captura de tela de 2024-09-15 15-35-33.png", "tamanho": 44726, "mimetype": "image/png", "encode": "7bit" } ] } }
Referência e link
- notas de aula baseado nos tutoriais/documentações nestjs
Top comments (0)