NestJS - Validando o envio de arquivos

leonardominora

Leonardo Minora

Posted on September 19, 2024

NestJS - Validando o envio de arquivos

Informações gerais

  • aula com FIXME 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

  • validar os arquivos enviados com validadores do nestjs
  • validar os arquivos enviados com validador personalizado

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. incluir módulo nestjs para os novos endpoints
  5. codar 1 endpoint com validação nestjs para envio de imagem png
  6. codar 1 endpoint com validação nestjs para envio de imagem jpeg
  7. codar 1 endpoint com validação personalizada para envio de imagens

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 05-upload-validacao origin/05-upload-validacao.

2. acessar pasta do projeto e instalar bibliotecas do projeto

[upload-api] $ npm install

Enter fullscreen mode Exit fullscreen mode

3. executar a api

[upload-api] $ npm run start:dev

Enter fullscreen mode Exit fullscreen mode

após lançar a api, o terminal deverá parecer como o console abaixo.

[14:44:53] Starting compilation in watch mode...

[14:44:56] Found 0 errors. Watching for file changes.

[Nest] 359207  - 20/09/2024, 14:44:57     LOG [NestFactory] Starting Nest application...
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] ConfigHostModule dependencies initialized +22ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] AppModule dependencies initialized +1ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] ConfigModule dependencies initialized +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] UploadModule dependencies initialized +1ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] ImageKitModule dependencies initialized +1ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [InstanceLoader] NuvemModule dependencies initialized +1ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RoutesResolver] AppController {/}: +32ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RoutesResolver] UploadController {/upload}: +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +1ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RoutesResolver] NuvemController {/nuvem}: +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/nuvem/upload, POST} route +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/nuvem/nome/:arquivo_nome, GET} route +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [RouterExplorer] Mapped {/nuvem/id/:arquivo_id, GET} route +0ms
[Nest] 359207  - 20/09/2024, 14:44:57     LOG [NestApplication] Nest application successfully started +3ms


Enter fullscreen mode Exit fullscreen mode

4. incluir módulo nestjs para os novos endpoints

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

Enter fullscreen mode Exit fullscreen mode
[upload-api]$ npx @nestjs/cli generate resource validacao --no-spec
? What transport layer do you use? REST API
? Would you like to generate CRUD entry points? No
CREATE src/validacao/validacao.controller.ts (234 bytes)
CREATE src/validacao/validacao.module.ts (276 bytes)
CREATE src/validacao/validacao.service.ts (93 bytes)
UPDATE src/app.module.ts (940 bytes)

Enter fullscreen mode Exit fullscreen mode

após adicionar o recurso/módulo, o terminal deverá parecer como o console abaixo.

[14:46:17] File change detected. Starting incremental compilation...

[14:46:17] Found 0 errors. Watching for file changes.

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

Enter fullscreen mode Exit fullscreen mode

5. codar 1 endpoint com validação nestjs para envio de imagem png

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

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

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

@Controller('validacao')
++@ApiTags('validação')
export class ValidacaoController {
  constructor(private readonly validacaoService: ValidacaoService) {}
++
++  @Post('upload/png')
++  @UseInterceptors(FileInterceptor('arquivo_png'))
++  @ApiConsumes('multipart/form-data')
++  @ApiBody({
++    schema: {
++      type: 'object',
++      properties: {
++        arquivo_png: {
++          type: 'string',
++          format: 'binary',
++        },
++      },
++    },
++  })
++  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
++  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
++  @ApiBadRequestResponse({
++    status: HttpStatus.BAD_REQUEST,
++    description: 'PROBLEMA com a imagem png enviada.',
++  })
++  upload_png(@UploadedFile() arquivo: Express.Multer.File) {
++    return { estado: 'ok' };
++  }
}

Enter fullscreen mode Exit fullscreen mode

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

[20:19:27] File change detected. Starting incremental compilation...

[20:19:27] Found 0 errors. Watching for file changes.

[Nest] 415309  - 20/09/2024, 20:19:28     LOG [NestFactory] Starting Nest application...
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] ConfigHostModule dependencies initialized +16ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] AppModule dependencies initialized +0ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] ConfigModule dependencies initialized +0ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] UploadModule dependencies initialized +0ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] ValidacaoModule dependencies initialized +0ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] ImageKitModule dependencies initialized +1ms
[Nest] 415309  - 20/09/2024, 20:19:28     LOG [InstanceLoader] NuvemModule dependencies initialized +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RoutesResolver] AppController {/}: +18ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RoutesResolver] UploadController {/upload}: +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +1ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RoutesResolver] NuvemController {/nuvem}: +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/nuvem/upload, POST} route +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/nuvem/nome/:arquivo_nome, GET} route +1ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/nuvem/id/:arquivo_id, GET} route +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RoutesResolver] ValidacaoController {/validacao}: +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [RouterExplorer] Mapped {/validacao/upload/png, POST} route +0ms
[Nest] 415309  - 20/09/2024, 20:19:29     LOG [NestApplication] Nest application successfully started +3ms

Enter fullscreen mode Exit fullscreen mode

para essa versão do endpoint e qualquer arquivo enviado o resultado será como no console abaixo.

{
  "estato": "ok"
}

Enter fullscreen mode Exit fullscreen mode

objetivo: modificar o endpoint para validar o arquivo enviado, aceitando apenas o png.

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

import {
  Controller,
++  FileTypeValidator,
  HttpStatus,
++  ParseFilePipe,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
import { ValidacaoService } from './validacao.service';
import {
  ApiBadRequestResponse,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('validacao')
@ApiTags('validação')
export class ValidacaoController {
  constructor(private readonly validacaoService: ValidacaoService) {}

  @Post('upload/png')
  @UseInterceptors(FileInterceptor('arquivo_png'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        arquivo_png: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
  @ApiBadRequestResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'PROBLEMA com a imagem png enviada.',
  })
--  upload_png(@UploadedFile() arquivo: Express.Multer.File) {
++  upload_png(
++    @UploadedFile(
++      new ParseFilePipe({
++        validators: [new FileTypeValidator({ fileType: 'image/png' })],
++      }),
++    )
++    arquivo: Express.Multer.File,
++  ) {
    return { estado: 'ok' };
  }
}

Enter fullscreen mode Exit fullscreen mode

foi adicionado no decorador (decorator) @UploadedFile, no parâmetro da assinatura do método upload_png, um novo objeto new ParseFilePipe que será responsável por executar as validações de arquivos enviados.
As validações são inseridas no atributo validators em seguida, e neste caso foi usado apenas o FileTypeValidator para verificar o tipo de arquivo (ver aviso abaixo).

Aviso by nestjs no tutorial sobre File upload com tradução pelo ChatGPT e links by me.

Para verificar o tipo de arquivo, a classe FileTypeValidator usa o tipo detectado pelo multer. Por padrão, o multer extrai o tipo do arquivo a partir da extensão do arquivo no dispositivo do usuário. No entanto, ele não verifica o conteúdo real do arquivo. Como os arquivos podem ser renomeados para extensões arbitrárias, considere usar uma implementação personalizada (como verificar o número mágico do arquivo) se seu aplicativo requer uma solução mais segura.

para esta versão com validação do endpoint, quando enviamos um arquivo imagem png, a resposta continuará a mesma acima.
caso envie qualquer outro tipo de arquivo, a resposta será como o json abaixo.

{
  "message": "Validation failed (expected type is image/png)",
  "error": "Bad Request",
  "statusCode": 400
}

Enter fullscreen mode Exit fullscreen mode

6. codar 1 endpoint com validação nestjs para envio de imagem jpeg

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

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

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

@Controller('validacao')
@ApiTags('validação')
export class ValidacaoController {
  constructor(private readonly validacaoService: ValidacaoService) {}

  @Post('upload/png')
  @UseInterceptors(FileInterceptor('arquivo_png'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        arquivo_png: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
  @ApiBadRequestResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'PROBLEMA com a imagem png enviada.',
  })
  upload_png(
    @UploadedFile(
      new ParseFilePipe({
        validators: [new FileTypeValidator({ fileType: 'image/png' })],
      }),
    )
    arquivo: Express.Multer.File,
  ) {
    return { estado: 'ok' };
  }
++
++  @Post('upload/jpeg')
++  @UseInterceptors(FileInterceptor('arquivo_jpeg'))
++  @ApiConsumes('multipart/form-data')
++  @ApiBody({
++    schema: {
++      type: 'object',
++      properties: {
++        arquivo_jpeg: {
++          type: 'string',
++          format: 'binary',
++        },
++      },
++    },
++  })
++  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
++  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
++  @ApiBadRequestResponse({
++    status: HttpStatus.BAD_REQUEST,
++    description: 'PROBLEMA com a imagem jpeg enviada.',
++  })
++  upload_jpeg(
++    @UploadedFile()
++    arquivo: Express.Multer.File,
++  ) {
++    return { estado: 'ok' };
++  }
}

Enter fullscreen mode Exit fullscreen mode

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

[20:59:39] File change detected. Starting incremental compilation...

[20:59:39] Found 0 errors. Watching for file changes.

[Nest] 418615  - 20/09/2024, 20:59:41     LOG [NestFactory] Starting Nest application...
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] ConfigHostModule dependencies initialized +34ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] AppModule dependencies initialized +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] UploadModule dependencies initialized +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] ValidacaoModule dependencies initialized +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] ImageKitModule dependencies initialized +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [InstanceLoader] NuvemModule dependencies initialized +2ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RoutesResolver] AppController {/}: +42ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/, GET} route +5ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RoutesResolver] UploadController {/upload}: +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +0ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +0ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RoutesResolver] NuvemController {/nuvem}: +0ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/nuvem/upload, POST} route +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/nuvem/nome/:arquivo_nome, GET} route +0ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/nuvem/id/:arquivo_id, GET} route +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RoutesResolver] ValidacaoController {/validacao}: +0ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/validacao/upload/png, POST} route +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [RouterExplorer] Mapped {/validacao/upload/jpeg, POST} route +1ms
[Nest] 418615  - 20/09/2024, 20:59:41     LOG [NestApplication] Nest application successfully started +4ms

Enter fullscreen mode Exit fullscreen mode

para essa versão do endpoint e qualquer arquivo enviado o resultado será como no console abaixo.

{
  "estato": "ok"
}

Enter fullscreen mode Exit fullscreen mode

objetivo: modificar o endpoint para validar o arquivo enviado, aceitando apenas o jpeg e jpg.

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

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

@Controller('validacao')
@ApiTags('validação')
export class ValidacaoController {
  constructor(private readonly validacaoService: ValidacaoService) {}

  @Post('upload/png')
  @UseInterceptors(FileInterceptor('arquivo_png'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        arquivo_png: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
  @ApiBadRequestResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'PROBLEMA com a imagem png enviada.',
  })
  upload_png(
    @UploadedFile(
      new ParseFilePipe({
        validators: [new FileTypeValidator({ fileType: 'image/png' })],
      }),
    )
    arquivo: Express.Multer.File,
  ) {
    return { estado: 'ok' };
  }

  @Post('upload/jpeg')
  @UseInterceptors(FileInterceptor('arquivo_jpeg'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        arquivo_jpeg: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento na nuvem' })
  @ApiResponse({ status: 201, description: 'Upload de arquivo concluído.' })
  @ApiBadRequestResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'PROBLEMA com a imagem jpeg enviada.',
  })
  upload_jpeg(
--    @UploadedFile()
++    @UploadedFile(
++      new ParseFilePipe({
++        validators: [new FileTypeValidator({ fileType: /jpeg|jpg/ })],
++      }),
++    )
    arquivo: Express.Multer.File,
  ) {
    return { estado: 'ok' };
  }
}

Enter fullscreen mode Exit fullscreen mode

assim como no endpoint anterior /upload/png, aqui também foi adicionado no decorador (decorator) @UploadedFile, no parâmetro da assinatura do método upload_jpeg, um novo objeto new ParseFilePipe que será responsável por executar as validações de arquivos enviados.
As validações são inseridas no atributo validators em seguida, e neste caso foi usado apenas o FileTypeValidator para verificar o tipo de arquivo.
contudo neste caso, o valor de fileType em FileTypeValidator teve uma expressão regular /jpeg|jpg/ que será processada no interpretada e validada em FileTypeValidator verifique a extensão do arquivo se é igual a jpeg ou jpg por causa do pipe adicionado.

para esta versão com validação do endpoint, quando enviamos um arquivo imagem png, a resposta continuará a mesma acima.
caso envie qualquer outro tipo de arquivo, a resposta será como o json abaixo.

{
  "message": "Validation failed (expected type is /jpeg|jpg/)",
  "error": "Bad Request",
  "statusCode": 400
}

Enter fullscreen mode Exit fullscreen mode

7. codar 1 endpoint com validação personalizada para envio de imagens

FIXME

💖 💪 🙅 🚩
leonardominora
Leonardo Minora

Posted on September 19, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

NestJS - Validando o envio de arquivos
infoweb NestJS - Validando o envio de arquivos

September 19, 2024