<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Leonardo Minora</title>
    <description>The latest articles on DEV Community by Leonardo Minora (@leonardominora).</description>
    <link>https://dev.to/leonardominora</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F271293%2F63b1fbc0-3ebe-4d93-a737-a9578fa38e56.jpeg</url>
      <title>DEV Community: Leonardo Minora</title>
      <link>https://dev.to/leonardominora</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leonardominora"/>
    <language>en</language>
    <item>
      <title>js / ts - expressão regular</title>
      <dc:creator>Leonardo Minora</dc:creator>
      <pubDate>Fri, 20 Sep 2024 23:56:08 +0000</pubDate>
      <link>https://dev.to/leonardominora/js-ts-expressao-regular-4g3d</link>
      <guid>https://dev.to/leonardominora/js-ts-expressao-regular-4g3d</guid>
      <description>&lt;p&gt;Claro! Aqui está um exemplo de como usar expressões regulares (regex) em TypeScript:&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo: Validar um endereço de email
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Função para validar e-mail usando regex&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validarEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9._%+-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+@&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;]{2,}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Testando a função&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;teste@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invalid-email@.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; é válido? &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;validarEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Saída: teste@example.com é válido? true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;email2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; é válido? &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;validarEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Saída: invalid-email@.com é válido? false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Descrição do Regex:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;^&lt;/code&gt;: Início da string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[a-zA-Z0-9._%+-]+&lt;/code&gt;: Um ou mais caracteres alfanuméricos, incluindo pontos, sublinhados, porcentagens, sinais de mais e menos.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@&lt;/code&gt;: Um caractere "@".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[a-zA-Z0-9.-]+&lt;/code&gt;: Um ou mais caracteres alfanuméricos ou pontos e hífens.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\.&lt;/code&gt;: Um caractere de ponto literal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[a-zA-Z]{2,}&lt;/code&gt;: Duas ou mais letras (para o domínio de nível superior, como .com, .org, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$&lt;/code&gt;: Fim da string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse exemplo mostra como você pode usar regex para validar um formato de email em TypeScript. Se precisar de mais exemplos ou explicações, fique à vontade para perguntar!&lt;/p&gt;

&lt;p&gt;by &lt;a href="https://chat.chatbotapp.ai/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>regex</category>
      <category>webdev</category>
    </item>
    <item>
      <title>js / ts - comando !!</title>
      <dc:creator>Leonardo Minora</dc:creator>
      <pubDate>Fri, 20 Sep 2024 22:39:06 +0000</pubDate>
      <link>https://dev.to/leonardominora/js-ts-comando--3188</link>
      <guid>https://dev.to/leonardominora/js-ts-comando--3188</guid>
      <description>&lt;p&gt;Em &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; (e &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;), o operador &lt;code&gt;!!&lt;/code&gt; é uma maneira comum de converter um valor em um booleano. Essencialmente, o &lt;code&gt;!!&lt;/code&gt; transforma qualquer valor em um valor booleano verdadeiro (&lt;code&gt;true&lt;/code&gt;) ou falso (&lt;code&gt;false&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Como Funciona:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;O primeiro &lt;code&gt;!&lt;/code&gt; nega o valor: se o valor for "truthy" (verdadeiro), ele se tornará &lt;code&gt;false&lt;/code&gt;. Se o valor for "falsy" (falso), ele se tornará &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;O segundo &lt;code&gt;!&lt;/code&gt; nega novamente o resultado da primeira negação. Assim, se o valor original era "truthy", o resultado final será &lt;code&gt;true&lt;/code&gt;, e se era "falsy", o resultado final será &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Valores Truthy e Falsy
&lt;/h3&gt;

&lt;p&gt;Em JavaScript, alguns exemplos de valores "falsy" incluem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;""&lt;/code&gt; (string vazia)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;null&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NaN&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qualquer outro valor é considerado "truthy", como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Objetos (inclusive arrays)&lt;/li&gt;
&lt;li&gt;Strings não vazias&lt;/li&gt;
&lt;li&gt;Números diferentes de zero&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exemplos:
&lt;/h3&gt;

&lt;p&gt;Aqui estão alguns exemplos que mostram como o &lt;code&gt;!!&lt;/code&gt; funciona:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Usando !! para converter em booleano&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true (5 é truthy)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false (0 é falsy)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false (null é falsy)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true (string não vazia é truthy)&lt;/span&gt;

&lt;span class="c1"&gt;// Exemplo mais complexo&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;myArray&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true (array vazio é truthy)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Uso Típico
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;!!&lt;/code&gt; é frequentemente usado em códigos onde você deseja garantir que um valor seja tratado como um booleano, especialmente em condições. Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User exists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User does not exist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste caso, o uso de &lt;code&gt;!!&lt;/code&gt; assegura que &lt;code&gt;user&lt;/code&gt; é tratado como um booleano ao avaliar a condição do &lt;code&gt;if&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;Portanto, o &lt;code&gt;!!&lt;/code&gt; é uma forma conveniente e concisa de forçar um valor a ser interpretado como um booleano em TypeScript e JavaScript. É uma prática comum para garantir que uma condição seja avaliada corretamente.&lt;/p&gt;

&lt;p&gt;by &lt;a href="https://chat.chatbotapp.ai/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>falsy</category>
      <category>truthy</category>
    </item>
    <item>
      <title>NestJS - Validando o envio de arquivos</title>
      <dc:creator>Leonardo Minora</dc:creator>
      <pubDate>Thu, 19 Sep 2024 21:10:31 +0000</pubDate>
      <link>https://dev.to/leonardominora/nestjs-validando-o-envio-de-arquivos-59d5</link>
      <guid>https://dev.to/leonardominora/nestjs-validando-o-envio-de-arquivos-59d5</guid>
      <description>&lt;h2&gt;
  
  
  Informações gerais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;aula com &lt;strong&gt;FIXME&lt;/strong&gt; para os &lt;strong&gt;alunos de programação orientada a serviços&lt;/strong&gt;, do 4o ano de infoweb, do CNAT-IFRN&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;repositório de código&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;código final branch zip&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  objetivo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;validar os arquivos enviados com validadores do nestjs&lt;/li&gt;
&lt;li&gt;validar os arquivos enviados com validador personalizado&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  notas de aula
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;sumário&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pegar o código base&lt;/li&gt;
&lt;li&gt;acessar pasta do projeto e instalar bibliotecas do projeto&lt;/li&gt;
&lt;li&gt;executar a api&lt;/li&gt;
&lt;li&gt;incluir módulo nestjs para os novos endpoints&lt;/li&gt;
&lt;li&gt;codar 1 endpoint com validação nestjs para envio de imagem png&lt;/li&gt;
&lt;li&gt;codar 1 endpoint com validação nestjs para envio de imagem jpeg&lt;/li&gt;
&lt;li&gt;codar 1 endpoint com validação personalizada para envio de imagens&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. pegar o código base
&lt;/h3&gt;

&lt;p&gt;pode utilizar o seu próprio código, ou baixar o &lt;a href=""&gt;zip&lt;/a&gt; ou fazer o clone do repositório &lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;github&lt;/a&gt; com o código-fonte do projeto da &lt;a href="https://dev.to/leonardominora/nest-armazenamento-nas-nuvens-561j"&gt;nota de aula anterior&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;lembrando que fazendo o clone do repositório &lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;github&lt;/a&gt;, precisará executar na pasta do projeto o comando &lt;code&gt;git checkout -b 05-upload-validacao origin/05-upload-validacao&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. acessar pasta do projeto e instalar bibliotecas do projeto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. executar a api
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npm run start:dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;após lançar a api, o terminal deverá parecer como o console abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. incluir módulo nestjs para os novos endpoints
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npx @nestjs/cli generate resource validacao &lt;span class="nt"&gt;--no-spec&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api]&lt;span class="nv"&gt;$ &lt;/span&gt;npx @nestjs/cli generate resource validacao &lt;span class="nt"&gt;--no-spec&lt;/span&gt;
? What transport layer &lt;span class="k"&gt;do &lt;/span&gt;you use? REST API
? Would you like to generate CRUD entry points? No
CREATE src/validacao/validacao.controller.ts &lt;span class="o"&gt;(&lt;/span&gt;234 bytes&lt;span class="o"&gt;)&lt;/span&gt;
CREATE src/validacao/validacao.module.ts &lt;span class="o"&gt;(&lt;/span&gt;276 bytes&lt;span class="o"&gt;)&lt;/span&gt;
CREATE src/validacao/validacao.service.ts &lt;span class="o"&gt;(&lt;/span&gt;93 bytes&lt;span class="o"&gt;)&lt;/span&gt;
UPDATE src/app.module.ts &lt;span class="o"&gt;(&lt;/span&gt;940 bytes&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;após adicionar o recurso/módulo, o terminal deverá parecer como o console abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. codar 1 endpoint com validação nestjs para envio de imagem png
&lt;/h3&gt;

&lt;p&gt;objetivo: criar o endpoint para upload de 1 arquivo imagem png com documentação swagger.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/validacao/validacao.controller.ts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--import { Controller } from '@nestjs/common';
&lt;/span&gt;&lt;span class="gi"&gt;++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';
&lt;/span&gt;&lt;span class="p"&gt;import { ValidacaoService } from './validacao.service';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('validacao')
&lt;span class="gi"&gt;++@ApiTags('validação')
&lt;/span&gt;&lt;span class="p"&gt;export class ValidacaoController {
&lt;/span&gt;  constructor(private readonly validacaoService: ValidacaoService) {}
&lt;span class="gi"&gt;++
++  @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' };
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para essa versão do endpoint e qualquer arquivo enviado o resultado será como no console abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estato"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: modificar o endpoint para validar o arquivo enviado, aceitando apenas o png.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/validacao/validacao.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
&lt;span class="gi"&gt;++  FileTypeValidator,
&lt;/span&gt;  HttpStatus,
&lt;span class="gi"&gt;++  ParseFilePipe,
&lt;/span&gt;  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { ValidacaoService } from './validacao.service';
import {
&lt;/span&gt;  ApiBadRequestResponse,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('validacao')
@ApiTags('validação')
&lt;span class="p"&gt;export class ValidacaoController {
&lt;/span&gt;  constructor(private readonly validacaoService: ValidacaoService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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.',
  })
&lt;span class="gd"&gt;--  upload_png(@UploadedFile() arquivo: Express.Multer.File) {
&lt;/span&gt;&lt;span class="gi"&gt;++  upload_png(
++    @UploadedFile(
++      new ParseFilePipe({
++        validators: [new FileTypeValidator({ fileType: 'image/png' })],
++      }),
++    )
++    arquivo: Express.Multer.File,
++  ) {
&lt;/span&gt;    return { estado: 'ok' };
  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;foi adicionado no decorador (&lt;em&gt;decorator&lt;/em&gt;) &lt;code&gt;@UploadedFile&lt;/code&gt;, no parâmetro da assinatura do método &lt;code&gt;upload_png&lt;/code&gt;, um novo objeto &lt;code&gt;new ParseFilePipe&lt;/code&gt; que será responsável por executar as validações de arquivos enviados.&lt;br&gt;
As validações são inseridas no atributo &lt;code&gt;validators&lt;/code&gt; em seguida, e neste caso foi usado apenas o &lt;a href="https://github.com/nestjs/nest/blob/master/packages/common/pipes/file/file-type.validator.ts" rel="noopener noreferrer"&gt;FileTypeValidator&lt;/a&gt; para verificar o tipo de arquivo (ver aviso abaixo).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aviso&lt;/strong&gt;  by &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;nestjs&lt;/a&gt; no tutorial sobre &lt;a href="https://docs.nestjs.com/techniques/file-upload" rel="noopener noreferrer"&gt;File upload&lt;/a&gt; com tradução pelo &lt;a href="https://chat.chatbotapp.ai/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt; e links &lt;em&gt;by me&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Para verificar o tipo de arquivo, a classe &lt;a href="https://github.com/nestjs/nest/blob/master/packages/common/pipes/file/file-type.validator.ts" rel="noopener noreferrer"&gt;FileTypeValidator&lt;/a&gt; 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 &lt;a href="https://www.ibm.com/support/pages/what-magic-number" rel="noopener noreferrer"&gt;número mágico do arquivo&lt;/a&gt;) se seu aplicativo requer uma solução mais segura.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validation failed (expected type is image/png)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bad Request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. codar 1 endpoint com validação nestjs para envio de imagem jpeg
&lt;/h3&gt;

&lt;p&gt;objetivo: criar o endpoint para upload de 1 arquivo imagem jpeg com documentação swagger.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/validacao/validacao.controller.ts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  FileTypeValidator,
  HttpStatus,
  ParseFilePipe,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { ValidacaoService } from './validacao.service';
import {
&lt;/span&gt;  ApiBadRequestResponse,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('validacao')
@ApiTags('validação')
&lt;span class="p"&gt;export class ValidacaoController {
&lt;/span&gt;  constructor(private readonly validacaoService: ValidacaoService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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' };
  }
&lt;span class="gi"&gt;++
++  @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' };
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para essa versão do endpoint e qualquer arquivo enviado o resultado será como no console abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estato"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: modificar o endpoint para validar o arquivo enviado, aceitando apenas o jpeg e jpg.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/validacao/validacao.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  FileTypeValidator,
  HttpStatus,
  ParseFilePipe,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { ValidacaoService } from './validacao.service';
import {
&lt;/span&gt;  ApiBadRequestResponse,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('validacao')
@ApiTags('validação')
&lt;span class="p"&gt;export class ValidacaoController {
&lt;/span&gt;  constructor(private readonly validacaoService: ValidacaoService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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' };
  }
&lt;span class="err"&gt;
&lt;/span&gt;  @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(
&lt;span class="gd"&gt;--    @UploadedFile()
&lt;/span&gt;&lt;span class="gi"&gt;++    @UploadedFile(
++      new ParseFilePipe({
++        validators: [new FileTypeValidator({ fileType: /jpeg|jpg/ })],
++      }),
++    )
&lt;/span&gt;    arquivo: Express.Multer.File,
  ) {
    return { estado: 'ok' };
  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;assim como no endpoint anterior &lt;code&gt;/upload/png&lt;/code&gt;, aqui também foi adicionado no decorador (&lt;em&gt;decorator&lt;/em&gt;) &lt;code&gt;@UploadedFile&lt;/code&gt;, no parâmetro da assinatura do método &lt;code&gt;upload_jpeg&lt;/code&gt;, um novo objeto &lt;code&gt;new ParseFilePipe&lt;/code&gt; que será responsável por executar as validações de arquivos enviados.&lt;br&gt;
As validações são inseridas no atributo &lt;code&gt;validators&lt;/code&gt; em seguida, e neste caso foi usado apenas o &lt;a href="https://github.com/nestjs/nest/blob/master/packages/common/pipes/file/file-type.validator.ts" rel="noopener noreferrer"&gt;FileTypeValidator&lt;/a&gt; para verificar o tipo de arquivo.&lt;br&gt;
contudo neste caso, o valor de &lt;code&gt;fileType&lt;/code&gt; em &lt;code&gt;FileTypeValidator&lt;/code&gt; teve uma &lt;a href="https://dev.to/leonardominora/js-ts-expressao-regular-4g3d"&gt;expressão regular&lt;/a&gt; &lt;code&gt;/jpeg|jpg/&lt;/code&gt; que será processada no interpretada e validada em &lt;code&gt;FileTypeValidator&lt;/code&gt; verifique a extensão do arquivo se é igual a &lt;code&gt;jpeg&lt;/code&gt; ou &lt;code&gt;jpg&lt;/code&gt; por causa do pipe adicionado.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validation failed (expected type is /jpeg|jpg/)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bad Request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. codar 1 endpoint com validação personalizada para envio de imagens
&lt;/h3&gt;

&lt;p&gt;FIXME&lt;/p&gt;

</description>
      <category>infoweb</category>
      <category>nextjs</category>
      <category>upload</category>
      <category>typescript</category>
    </item>
    <item>
      <title>NestJS - Armazenamento nas nuvens</title>
      <dc:creator>Leonardo Minora</dc:creator>
      <pubDate>Thu, 19 Sep 2024 18:16:56 +0000</pubDate>
      <link>https://dev.to/leonardominora/nest-armazenamento-nas-nuvens-561j</link>
      <guid>https://dev.to/leonardominora/nest-armazenamento-nas-nuvens-561j</guid>
      <description>&lt;h2&gt;
  
  
  Informações gerais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;aula com &lt;strong&gt;endpoint para upload de arquivos com armazenamento em nuvem&lt;/strong&gt; (&lt;em&gt;cloud&lt;/em&gt;) para os &lt;strong&gt;alunos de programação orientada a serviços&lt;/strong&gt;, do 4o ano de infoweb, do CNAT-IFRN&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;repositório de código&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;código final &lt;a href="https://github.com/infoweb-pos/2024-api-upload/tree/04-upload-cloud" rel="noopener noreferrer"&gt;branch&lt;/a&gt; &lt;a href="https://github.com/infoweb-pos/2024-api-upload/archive/refs/tags/05-upload-armazenamento-nuvem.zip" rel="noopener noreferrer"&gt;zip&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  objetivo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;criar 1 endpoint de upload de 1 arquivo com armazenamento em nuvem (&lt;em&gt;cloud&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;criar 1 endpoint de download de 1 arquivo que foi armazenado em nuvem (&lt;em&gt;cloud&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  notas de aula
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;sumário&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pegar o código base&lt;/li&gt;
&lt;li&gt;acessar pasta do projeto e instalar bibliotecas do projeto&lt;/li&gt;
&lt;li&gt;executar a api&lt;/li&gt;
&lt;li&gt;criar conta no imagekit.io e configurar acesso ao serviço&lt;/li&gt;
&lt;li&gt;incluir módulo nestjs para os novos endpoints&lt;/li&gt;
&lt;li&gt;codar o upload de arquivo para armazenamento na nuvem&lt;/li&gt;
&lt;li&gt;codar o "download" de arquivo armazenado na nuvem&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. pegar o código base
&lt;/h3&gt;

&lt;p&gt;pode utilizar o seu próprio código, ou baixar o &lt;a href="https://github.com/infoweb-pos/2024-api-upload/archive/refs/tags/03-upload-arquivos-multiplos.zip" rel="noopener noreferrer"&gt;zip&lt;/a&gt; ou fazer o clone do repositório &lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;github&lt;/a&gt; com o código-fonte do projeto da &lt;a href="https://dev.to/leonardominora/nest-armazenamento-local-de-upload-7ne"&gt;nota de aula anterior&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;lembrando que fazendo o clone do repositório &lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;github&lt;/a&gt;, precisará executar na pasta do projeto o comando &lt;code&gt;git checkout -b 04-upload-cloud origin/04-upload-cloud&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. acessar pasta do projeto e instalar bibliotecas do projeto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;imagekit-nestjs @nestjs/config

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. executar a api
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npm run start:dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. criar conta no imagekit.io e configurar acesso ao serviço
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;acessar &lt;a href="https://imagekit.io/" rel="noopener noreferrer"&gt;imagekit.io&lt;/a&gt; e criar um conta gratuita;&lt;/li&gt;
&lt;li&gt;acessar &lt;a href="https://imagekit.io/" rel="noopener noreferrer"&gt;imagekit.io&lt;/a&gt; conectado e criar uma chave privada;

&lt;ol&gt;
&lt;li&gt;conectado e já com uma conta funcionando, acessar o &lt;a href="https://imagekit.io/dashboard/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;no menu lateral, no meu caso direito, rolar e acessar &lt;code&gt;Developer options&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;na página que abre, tem já pronto a &lt;em&gt;Public key&lt;/em&gt; habilitada para copiar&lt;/li&gt;
&lt;li&gt;nesta mesma página e logo ao lado de &lt;em&gt;Public key&lt;/em&gt;, tem &lt;em&gt;Private key (keep confidential)&lt;/em&gt; que vem desabilitada, caso sua conta seja criada com login de terceiros&lt;/li&gt;
&lt;li&gt;habilite &lt;em&gt;Private key (keep confidential)&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;codar no projeto o acesso a &lt;a href="https://imagekit.io/" rel="noopener noreferrer"&gt;imagekit.io&lt;/a&gt;.

&lt;ol&gt;
&lt;li&gt;criar e editar o arquivo &lt;code&gt;.env&lt;/code&gt; na pasta raiz do projeto, como exemplo abaixo&lt;/li&gt;
&lt;li&gt;criar e editar o arquivo &lt;code&gt;./src/configs/imagekit.config.ts&lt;/code&gt; conforme arquivo abaixo&lt;/li&gt;
&lt;li&gt;editar o arquivo &lt;code&gt;./src/app.module.ts&lt;/code&gt; para configurar o acesso ao serviço do &lt;a href="https://imagekit.io/" rel="noopener noreferrer"&gt;imagekit.io&lt;/a&gt; com as libs &lt;a href="https://www.npmjs.com/package/imagekit-nestjs" rel="noopener noreferrer"&gt;imagekit-nestjs&lt;/a&gt; e &lt;a href="https://docs.nestjs.com/techniques/configuration" rel="noopener noreferrer"&gt;@nestjs/config&lt;/a&gt;, como arquivo abaixo&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;arquivo &lt;code&gt;./src/.env&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  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/'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;arquivo &lt;code&gt;./src/configs/imagekit.config.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ImageKitModuleOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;imagekit-nestjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ImageKitConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ImageKitModuleOptions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUD_PRIVATE_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUD_PUBLIC_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;urlEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUD_URL_ENDPOINT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;arquivo &lt;code&gt;./src/app.module.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { Module } from '@nestjs/common';
&lt;/span&gt;&lt;span class="gi"&gt;++import { ConfigModule, ConfigService } from '@nestjs/config';
++import { ImageKitModule } from 'imagekit-nestjs';
++import { ImageKitConfig } from './configs/imagekit.config';
&lt;/span&gt;&lt;span class="p"&gt;import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UploadModule } from './upload/upload.module';
import { ArmazenamentoModule } from './armazenamento/armazenamento.module';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Module({
&lt;span class="gd"&gt;--  imports: [UploadModule, ArmazenamentoModule],
&lt;/span&gt;&lt;span class="gi"&gt;++  imports: [
++    ConfigModule.forRoot(),
++    ImageKitModule.forRootAsync({
++      useFactory: ImageKitConfig,
++      inject: [ConfigService],
++      imports: [ConfigModule],
++      isGlobal: true,
++    }),
++    UploadModule,
++    ArmazenamentoModule,
++  ],
&lt;/span&gt;  controllers: [AppController],
  providers: [AppService],
})
&lt;span class="p"&gt;export class AppModule {}
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;após salvar os arquivos, o terminal de execução da API deve parecer com o console abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. incluir módulo nestjs para os novos endpoints
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npx @nestjs/cli generate resource nuvem &lt;span class="nt"&gt;--no-spec&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;resultado da execução do comando de gerar recurso (&lt;em&gt;module&lt;/em&gt;) &lt;code&gt;nuvem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npx @nestjs/cli g res nuvem &lt;span class="nt"&gt;--no-spec&lt;/span&gt;
? What transport layer &lt;span class="k"&gt;do &lt;/span&gt;you use? REST API
? Would you like to generate CRUD entry points? No
CREATE src/nuvem/nuvem.controller.ts &lt;span class="o"&gt;(&lt;/span&gt;210 bytes&lt;span class="o"&gt;)&lt;/span&gt;
CREATE src/nuvem/nuvem.module.ts &lt;span class="o"&gt;(&lt;/span&gt;248 bytes&lt;span class="o"&gt;)&lt;/span&gt;
CREATE src/nuvem/nuvem.service.ts &lt;span class="o"&gt;(&lt;/span&gt;89 bytes&lt;span class="o"&gt;)&lt;/span&gt;
UPDATE src/app.module.ts &lt;span class="o"&gt;(&lt;/span&gt;478 bytes&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;resultado do terminal que esta com a API em execução.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. codar o upload de arquivo para armazenamento na nuvem
&lt;/h3&gt;

&lt;p&gt;objetivo: criar o endpoint para upload de 1 arquivo com documentação swagger.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/nuvem/nuvem.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--import { Controller } from '@nestjs/common';
--import { NuvemService } from './nuvem.service';
&lt;/span&gt;&lt;span class="gi"&gt;++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';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('nuvem')
&lt;span class="gi"&gt;++@ApiTags('nuvem')
&lt;/span&gt;&lt;span class="p"&gt;export class NuvemController {
&lt;/span&gt;  constructor(private readonly nuvemService: NuvemService) {}
&lt;span class="gi"&gt;++
++  @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' };
++  }
++
&lt;/span&gt;}
&lt;span class="err"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para essa versão do endpoint, o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estato"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: armazenar o arquivo recebido na nuvem &lt;a href="https://imagekit.io/" rel="noopener noreferrer"&gt;imagekit.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/nuvem/nuvem.service.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { Injectable } from '@nestjs/common';
&lt;/span&gt;&lt;span class="gi"&gt;++import { ImageKitService } from 'imagekit-nestjs';
++
++class ArquivoDto {
++  id: string;
++  nome: string;
++  tamanho: number;
++  mimetype: string;
++  encoding: string;
++  armazenamento: string;
++}
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Injectable()
&lt;span class="gd"&gt;--export class NuvemService {}
&lt;/span&gt;&lt;span class="gi"&gt;++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,
++    };
++  }
++}
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: ligar o endpoint (&lt;em&gt;controller&lt;/em&gt;) ao processamento de armazenamento (&lt;em&gt;service&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/nuvem/nuvem.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  HttpStatus,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { NuvemService } from './nuvem.service';
import {
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('nuvem')
@ApiTags('nuvem')
&lt;span class="p"&gt;export class NuvemController {
&lt;/span&gt;  constructor(private readonly nuvemService: NuvemService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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.' })
&lt;span class="gd"&gt;--  @ApiResponse({ status: 400, description: 'ERRO no upload do arquivo.' })
&lt;/span&gt;&lt;span class="gi"&gt;++  @ApiResponse({
++    status: HttpStatus.NOT_ACCEPTABLE,
++    description: 'ERRO no upload do arquivo.',
++  })
&lt;/span&gt;  upload(@UploadedFile() arquivo: Express.Multer.File) {
&lt;span class="gd"&gt;--    return { estado: 'ok' };
&lt;/span&gt;&lt;span class="gi"&gt;++    return this.nuvemService.upload(arquivo);
&lt;/span&gt;  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para a versão final do endpoint, o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estado"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"66ec6724e375273f6095fca5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diatinf.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"encoding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7bit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mimetype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tamanho"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;132200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"armazenamento"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ik.imagekit.io/minora/diatinf_nLtEXmRGb.png"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. codar o "download" de arquivo armazenado na nuvem
&lt;/h3&gt;

&lt;p&gt;objetivo: criar o endpoint para download de 1 arquivo com documentação swagger.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/nuvem/nuvem.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
&lt;span class="gi"&gt;++  Get,
++  Param,
&lt;/span&gt;  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { NuvemService } from './nuvem.service';
import {
&lt;/span&gt;&lt;span class="gi"&gt;++  ApiBadRequestResponse,
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('nuvem')
@ApiTags('nuvem')
&lt;span class="p"&gt;export class NuvemController {
&lt;/span&gt;  constructor(private readonly nuvemService: NuvemService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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);
  }
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;++  @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' };
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;após salvar o arquivo &lt;code&gt;src/nuvem/nuvem.controller.ts&lt;/code&gt;, o terminal onde esta executando a API deve parecer com o console abaixo.&lt;br&gt;
Note que foi adicionado mais 2 endpoints &lt;code&gt;Mapped {/armazenamento/:nome, GET}&lt;/code&gt; e &lt;code&gt;Mapped {/nuvem/id/:arquivo_id, GET&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para ambas os endpoints, segue o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estato"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: recuperar informações do arquivo armazenado na nuvem &lt;a href="https://imagekit.io/" rel="noopener noreferrer"&gt;imagekit.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/nuvem/nuvem.service.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
&lt;/span&gt;&lt;span class="gi"&gt;++import {
++  HttpException,
++  HttpStatus,
++  Injectable,
++  NotFoundException,
++} from '@nestjs/common';import { ImageKitService } from 'imagekit-nestjs';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;class ArquivoDto {
&lt;/span&gt;  id: string;
  nome: string;
  tamanho: number;
  mimetype: string;
  encoding: string;
  armazenamento: string;
}
&lt;span class="err"&gt;
&lt;/span&gt;@Injectable()
&lt;span class="p"&gt;export class NuvemService {
&lt;/span&gt;  arquivos: ArquivoDto[] = [];
&lt;span class="err"&gt;
&lt;/span&gt;  constructor(private readonly cloud: ImageKitService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  async upload(arquivo: Express.Multer.File) {
    const resultado = await this.cloud.upload({
      file: arquivo.buffer,
      fileName: arquivo.originalname,
    });
&lt;span class="err"&gt;
&lt;/span&gt;    if (!resultado) {
      throw new HttpException(
        'Erro ao tentar armazenar arquivo na nuvem',
        HttpStatus.NOT_ACCEPTABLE,
      );
    }
&lt;span class="err"&gt;
&lt;/span&gt;    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,
    };
  }
&lt;span class="gi"&gt;++
++  pegarPorNome(nome: string) {
++    const informacao = this.arquivos.filter((item) =&amp;gt; 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) =&amp;gt; item.id === id);
++    if (informacao.length === 0) {
++      throw new NotFoundException(`Arquivo (${id}) não encontrado.`);
++    }
++    return informacao[0];
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: ligar o endpoint (&lt;em&gt;controller&lt;/em&gt;) ao processamento de armazenamento (&lt;em&gt;service&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;./src/nuvem/nuvem.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  Get,
  Param,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { NuvemService } from './nuvem.service';
import {
&lt;/span&gt;  ApiBadRequestResponse,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('nuvem')
@ApiTags('nuvem')
&lt;span class="p"&gt;export class NuvemController {
&lt;/span&gt;  constructor(private readonly nuvemService: NuvemService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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);
  }
&lt;span class="err"&gt;
&lt;/span&gt;  @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) {
&lt;span class="gd"&gt;--    return { estado: 'ok' };
&lt;/span&gt;&lt;span class="gi"&gt;++    return this.nuvemService.pegarPorNome(arquivo_nome);
&lt;/span&gt;  }
&lt;span class="err"&gt;
&lt;/span&gt;  @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) {
&lt;span class="gd"&gt;--    return { estado: 'ok' };
&lt;/span&gt;&lt;span class="gi"&gt;++    return this.nuvemService.pegarPorID(arquivo_id);
&lt;/span&gt;  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para a versão final dos endpoints, o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estado"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"66ec6724e375273f6095fca5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diatinf.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"encoding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7bit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mimetype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tamanho"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;132200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"armazenamento"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ik.imagekit.io/minora/diatinf_nLtEXmRGb.png"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>infoweb</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>upload</category>
    </item>
    <item>
      <title>NestJS - Armazenamento local de upload</title>
      <dc:creator>Leonardo Minora</dc:creator>
      <pubDate>Mon, 16 Sep 2024 17:59:19 +0000</pubDate>
      <link>https://dev.to/leonardominora/nest-armazenamento-local-de-upload-7ne</link>
      <guid>https://dev.to/leonardominora/nest-armazenamento-local-de-upload-7ne</guid>
      <description>&lt;h2&gt;
  
  
  Informações gerais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;aula com &lt;strong&gt;endpoint para upload de arquivos com armazenamento em disco local&lt;/strong&gt; para os &lt;strong&gt;alunos de programação orientada a serviços&lt;/strong&gt;, do 4o ano de infoweb, do CNAT-IFRN&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;repositório de código&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;código final &lt;a href="https://github.com/infoweb-pos/2024-api-upload/tree/03-upload-store" rel="noopener noreferrer"&gt;branch 03-upload-store&lt;/a&gt; ou &lt;a href="https://github.com/infoweb-pos/2024-api-upload/archive/refs/tags/04-upload-armazenamento-local.zip" rel="noopener noreferrer"&gt;zip&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  objetivo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;criar 1 endpoint de upload de 1 arquivo com armazenamento em disco local&lt;/li&gt;
&lt;li&gt;criar 1 endpoint de download de 1 arquivo que foi armazenado em disco local&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  notas de aula
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;sumário&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pegar o código base&lt;/li&gt;
&lt;li&gt;acessar pasta do projeto e instalar bibliotecas do projeto&lt;/li&gt;
&lt;li&gt;executar a api&lt;/li&gt;
&lt;li&gt;incluir módulo nestjs para os novos endpoints&lt;/li&gt;
&lt;li&gt;codar o upload de arquivo com armazenamento local&lt;/li&gt;
&lt;li&gt;codar o download de arquivo com armazenamento local&lt;/li&gt;
&lt;li&gt;codar para adicionar exceção para arquivo não encontrado&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. pegar o código base
&lt;/h3&gt;

&lt;p&gt;pode utilizar o seu próprio código, ou baixar o &lt;a href="https://github.com/infoweb-pos/2024-api-upload/archive/refs/tags/03-upload-arquivos-multiplos.zip" rel="noopener noreferrer"&gt;zip&lt;/a&gt; ou fazer o clone do repositório &lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;github&lt;/a&gt; com o código-fonte do projeto da &lt;a href="https://dev.to/leonardominora/nestjs-upload-e-armazenamento-local-de-arquivo-3gbn"&gt;nota de aula anterior&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;lembrando que fazendo o clone do repositório &lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;github&lt;/a&gt;, precisará executar na pasta do projeto o comando &lt;code&gt;git checkout -b 02-upload-arquivos-multiplos origin/02-upload-arquivos-multiplos&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. acessar pasta do projeto e instalar bibliotecas do projeto
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. executar a api
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npm run start:dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. incluir módulo nestjs para os novos endpoints
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npx @nestjs/cli generate resource armazenamento &lt;span class="nt"&gt;--no-spec&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[15:08:33] Starting compilation in watch mode...

[15:08:35] Found 0 errors. Watching for file changes.

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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. codar o upload de arquivo com armazenamento local
&lt;/h3&gt;

&lt;p&gt;objetivo: criar o endpoint para upload de 1 arquivo com documentação swagger.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/armazenamento/armazenamento.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--import { Controller } from '@nestjs/common';
&lt;/span&gt;&lt;span class="gi"&gt;++import {
++  Controller,
++  Post,
++  UploadedFile,
++  UseInterceptors,
++} from '@nestjs/common';
++import { ArmazenamentoService } from './armazenamento.service';
++import {
++  ApiBody,
++  ApiConsumes,
++  ApiOperation,
++  ApiResponse,
++  ApiTags,
++} from '@nestjs/swagger';
++import { FileInterceptor } from '@nestjs/platform-express';
++
++@Controller('armazenamento')
++@ApiTags('armazenamento')
&lt;/span&gt;&lt;span class="p"&gt;export class ArmazenamentoController {
&lt;/span&gt;  constructor(private readonly armazenamentoService: ArmazenamentoService) {}
&lt;span class="gi"&gt;++
++  @Post()
++  @UseInterceptors(FileInterceptor('imagem'))
++  @ApiConsumes('multipart/form-data')
++  @ApiBody({
++    schema: {
++      type: 'object',
++      properties: {
++        imagem: {
++          type: 'string',
++          format: 'binary',
++        },
++      },
++    },
++  })
++  @ApiOperation({ summary: 'Upload de arquivo com armazenamento' })
++  @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' })
++  @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' })
++  salvar(@UploadedFile() arq: Express.Multer.File) {
++    return {estato: 'ok'};
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;após salvar o arquivo &lt;code&gt;src/armazenamento/armazenamento.controller.ts&lt;/code&gt;, o terminal onde esta executando a API deve parecer com o console abaixo.&lt;br&gt;
Note que foi adicionado mais um endpoint &lt;code&gt;Mapped {/armazenamento, POST}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[19:37:49] File change detected. Starting incremental compilation...

[19:37:49] Found 0 errors. Watching for file changes.

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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para essa versão do endpoint, o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estato"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: armazenar o arquivo recebido em disco local.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/armazenamento/armazenamento.service.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { Injectable } from '@nestjs/common';
&lt;/span&gt;&lt;span class="gi"&gt;++import { promises as fs } from 'fs';
++import * as path from 'path';
++
++class ImagemDto {
++  id: string;
++  nome: string;
++  tamanho: number;
++  mimetype: string;
++  encoding: string;
++  armazenamento: string;
++}
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Injectable()
&lt;span class="p"&gt;export class ArmazenamentoService {
&lt;/span&gt;&lt;span class="gi"&gt;++  dir = path.join(__dirname, '..', '..', 'uploads');
++  imagens = new Array&amp;lt;ImagemDto&amp;gt;();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;++  async salvarEmDisco(arquivo: Express.Multer.File) {
++    const nomeCompleto = path.join(this.dir, arquivo.originalname);
++
++    await fs.writeFile(nomeCompleto, arquivo.buffer);
++    this.imagens.push({
++      id: arquivo.originalname,
++      nome: arquivo.originalname,
++      tamanho: arquivo.size,
++      mimetype: arquivo.mimetype,
++      encoding: arquivo.encoding,
++      armazenamento: nomeCompleto,
++    });
++    return {
++      estado: 'ok',
++      dados: {
++        id: arquivo.originalname,
++        nome: arquivo.originalname,
++      },
++    };
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: ligar o endpoint (&lt;em&gt;controller&lt;/em&gt;) ao processamento de armazenamento (&lt;em&gt;service&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/armazenamento/armazenamento.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { ArmazenamentoService } from './armazenamento.service';
import {
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('armazenamento')
@ApiTags('armazenamento')
&lt;span class="p"&gt;export class ArmazenamentoController {
&lt;/span&gt;  constructor(private readonly armazenamentoService: ArmazenamentoService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @Post()
  @UseInterceptors(FileInterceptor('imagem'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        imagem: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento' })
  @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' })
  @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' })
  salvar(@UploadedFile() arq: Express.Multer.File) {
&lt;span class="gd"&gt;--    return {estato: 'ok'};
&lt;/span&gt;&lt;span class="gi"&gt;++    return this.armazenamentoService.salvarEmDisco(arq);
&lt;/span&gt;  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para a versão final do endpoint, o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estado"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dados"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Captura de tela de 2024-09-17 15-12-17.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Captura de tela de 2024-09-17 15-12-17.png"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. codar o download de arquivo com armazenamento local
&lt;/h3&gt;

&lt;p&gt;objetivo: criar o endpoint para upload de 1 arquivo com documentação swagger.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/armazenamento/armazenamento.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
&lt;span class="gi"&gt;++  Get,
++  Param,
&lt;/span&gt;  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { ArmazenamentoService } from './armazenamento.service';
import {
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('armazenamento')
@ApiTags('armazenamento')
&lt;span class="p"&gt;export class ArmazenamentoController {
&lt;/span&gt;  constructor(private readonly armazenamentoService: ArmazenamentoService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @Post()
  @UseInterceptors(FileInterceptor('imagem'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        imagem: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento' })
  @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' })
  @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' })
  salvar(@UploadedFile() arq: Express.Multer.File) {
    return this.armazenamentoService.salvarEmDisco(arq);
  }
&lt;span class="gi"&gt;++
++  @Get(':nome')
++  @ApiOperation({ summary: 'Endpoint para receber arquivo' })
++  @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' })
++  @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' })
++  ler(@Param('nome') nome: string) {
++    return { estado: 'ok' };
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;após salvar o arquivo &lt;code&gt;src/armazenamento/armazenamento.controller.ts&lt;/code&gt;, o terminal onde esta executando a API deve parecer com o console abaixo.&lt;br&gt;
Note que foi adicionado mais um endpoint &lt;code&gt;Mapped {/armazenamento/:nome, GET}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[19:51:57] File change detected. Starting incremental compilation...

[19:51:57] Found 0 errors. Watching for file changes.

[Nest] 156968  - 17/09/2024, 19:51:58     LOG [NestFactory] Starting Nest application...
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [InstanceLoader] AppModule dependencies initialized +12ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [InstanceLoader] UploadModule dependencies initialized +1ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [InstanceLoader] ArmazenamentoModule dependencies initialized +0ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RoutesResolver] AppController {/}: +15ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RoutesResolver] UploadController {/upload}: +0ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RouterExplorer] Mapped {/upload/arquivos, POST} route +0ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RoutesResolver] ArmazenamentoController {/armazenamento}: +1ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RouterExplorer] Mapped {/armazenamento, POST} route +0ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [RouterExplorer] Mapped {/armazenamento/:nome, GET} route +0ms
[Nest] 156968  - 17/09/2024, 19:51:58     LOG [NestApplication] Nest application successfully started +5ms

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para essa versão do endpoint, o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estato"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: ler o arquivo do disco local.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/armazenamento/armazenamento.service.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { Injectable } from '@nestjs/common';
import { promises as fs } from 'fs';
import * as path from 'path';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;class ImagemDto {
&lt;/span&gt;  id: string;
  nome: string;
  tamanho: number;
  mimetype: string;
  encoding: string;
  armazenamento: string;
}
&lt;span class="err"&gt;
&lt;/span&gt;@Injectable()
&lt;span class="p"&gt;export class ArmazenamentoService {
&lt;/span&gt;  dir = path.join(__dirname, '..', '..', 'uploads');
  imagens = new Array&amp;lt;ImagemDto&amp;gt;();
&lt;span class="err"&gt;
&lt;/span&gt;  async salvarEmDisco(arquivo: Express.Multer.File) {
    const nomeCompleto = path.join(this.dir, arquivo.originalname);
&lt;span class="err"&gt;
&lt;/span&gt;    await fs.writeFile(nomeCompleto, arquivo.buffer);
    this.imagens.push({
      id: arquivo.originalname,
      nome: arquivo.originalname,
      tamanho: arquivo.size,
      mimetype: arquivo.mimetype,
      encoding: arquivo.encoding,
      armazenamento: nomeCompleto,
    });
    return {
      estado: 'ok',
      dados: {
        id: arquivo.originalname,
        nome: arquivo.originalname,
      },
    };
  }
&lt;span class="gi"&gt;++
++  async pegar(nome: string) {
++    const imagem = this.imagens.filter((item) =&amp;gt; item.id === nome)[0];
++    try {
++      const arquivo = await fs.readFile(imagem.armazenamento);
++      return {
++        estado: 'ok',
++        dados: {
++          informacao: imagem,
++          buffer: arquivo,
++        },
++      };
++    } catch (erro) {
++      return null;
++    }
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;objetivo: ligar o endpoint (&lt;em&gt;controller&lt;/em&gt;) ao processamento de armazenamento (&lt;em&gt;service&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/armazenamento/armazenamento.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  Get,
  Param,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { ArmazenamentoService } from './armazenamento.service';
import {
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('armazenamento')
@ApiTags('armazenamento')
&lt;span class="p"&gt;export class ArmazenamentoController {
&lt;/span&gt;  constructor(private readonly armazenamentoService: ArmazenamentoService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @Post()
  @UseInterceptors(FileInterceptor('imagem'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        imagem: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento' })
  @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' })
  @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' })
  salvar(@UploadedFile() arq: Express.Multer.File) {
    return this.armazenamentoService.salvarEmDisco(arq);
  }
&lt;span class="err"&gt;
&lt;/span&gt;  @Get(':nome')
  @ApiOperation({ summary: 'Endpoint para receber arquivo' })
  @ApiResponse({ status: 200, description: 'Arquivo enviado com sucesso.' })
  @ApiResponse({ status: 404, description: 'Erro no envio do arquivo.' })
  ler(@Param('nome') nome: string) {
&lt;span class="gd"&gt;--    return { estado: 'ok' };
&lt;/span&gt;&lt;span class="gi"&gt;++    return this.armazenamentoService.pegar(nome);
&lt;/span&gt;  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para a versão final do endpoint, o exemplo de teste com a documentação &lt;em&gt;swagger&lt;/em&gt; na figura abaixo e o resultado no console, também, abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estado"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dados"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"informacao"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"diatinf.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"diatinf.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tamanho"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;132200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mimetype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"encoding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"7bit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"armazenamento"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/home/minora/minora/2024/upload-api/uploads/diatinf.png"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"buffer"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Buffer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;137&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. codar para adicionar exceção para arquivo não encontrado
&lt;/h3&gt;

&lt;p&gt;a imagem abaixo mostra como é respondido pela API quando um arquivo não foi encontrado.&lt;br&gt;
isso ocorre porque em &lt;em&gt;service&lt;/em&gt; retorna &lt;code&gt;null&lt;/code&gt; mas não é tratado devidamende em &lt;em&gt;controller&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;objetivo: lançar exceção quando o arquivo requisitado não for encontrado.&lt;/p&gt;

&lt;p&gt;modificar o arquivo &lt;code&gt;src/armazenamento/armazenamento.controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  Get,
&lt;span class="gi"&gt;++  NotFoundException,
&lt;/span&gt;  Param,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import {
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { FileInterceptor } from '@nestjs/platform-express';
import { ArmazenamentoService } from './armazenamento.service';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('armazenamento')
@ApiTags('armazenamento')
&lt;span class="p"&gt;export class ArmazenamentoController {
&lt;/span&gt;  constructor(private readonly armazenamentoService: ArmazenamentoService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @Post()
  @UseInterceptors(FileInterceptor('imagem'))
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        imagem: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiOperation({ summary: 'Upload de arquivo com armazenamento' })
  @ApiResponse({ status: 201, description: 'Arquivo enviado com sucesso.' })
  @ApiResponse({ status: 400, description: 'Erro no envio do arquivo.' })
  salvar(@UploadedFile() arq: Express.Multer.File) {
    return this.armazenamentoService.salvarEmDisco(arq);
  }
&lt;span class="err"&gt;
&lt;/span&gt;  @Get(':nome')
  @ApiOperation({ summary: 'Endpoint para receber arquivo' })
  @ApiResponse({ status: 200, description: 'Arquivo enviado com sucesso.' })
  @ApiResponse({ status: 404, description: 'Arquivo não encontrado.' })
&lt;span class="gd"&gt;--  ler(@Param('nome') nome: string) {
&lt;/span&gt;&lt;span class="gi"&gt;++  async ler(@Param('nome') nome: string) {
&lt;/span&gt;&lt;span class="gd"&gt;--    return this.armazenamentoService.pegar(nome);
&lt;/span&gt;&lt;span class="gi"&gt;++    const resposta = await this.armazenamentoService.pegar(nome);
++    if (resposta) return resposta;
++    throw new NotFoundException('Arquivo não encontrado.');
&lt;/span&gt;  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>infoweb</category>
      <category>nextjs</category>
      <category>typescript</category>
      <category>upload</category>
    </item>
    <item>
      <title>NestJS - criar um endpoint para upload de diversos arquivos</title>
      <dc:creator>Leonardo Minora</dc:creator>
      <pubDate>Sun, 15 Sep 2024 19:38:56 +0000</pubDate>
      <link>https://dev.to/leonardominora/nestjs-upload-e-armazenamento-local-de-arquivo-3gbn</link>
      <guid>https://dev.to/leonardominora/nestjs-upload-e-armazenamento-local-de-arquivo-3gbn</guid>
      <description>&lt;h2&gt;
  
  
  Informações gerais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;aula com &lt;strong&gt;endpoint para upload de arquivos&lt;/strong&gt; para os &lt;strong&gt;alunos de programação orientada a serviços&lt;/strong&gt;, do 4o ano de infoweb, do CNAT-IFRN&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;repositório de código&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;código final &lt;a href="https://github.com/infoweb-pos/2024-api-upload/tree/03-upload-arquivos-multiplos" rel="noopener noreferrer"&gt;branch 03-upload-arquivos-multiplos&lt;/a&gt; &lt;a href="https://github.com/infoweb-pos/2024-api-upload/archive/refs/tags/03-upload-arquivos-multiplos.zip" rel="noopener noreferrer"&gt;zip&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  objetivo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;criar 1 endpoint para API de upload de múltiplos arquivos&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  notas de aula
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;sumário&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pegar o código do projeto anterior&lt;/li&gt;
&lt;li&gt;executar a API&lt;/li&gt;
&lt;li&gt;criar e configurar 1 endpoint para receber vários arquivos&lt;/li&gt;
&lt;li&gt;criar método no serviço para retornar as informações dos arquivos&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;para receber vários arquivos, o &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;nestjs&lt;/a&gt; disponibiliza os seguintes &lt;a href="https://docs.nestjs.com/interceptors" rel="noopener noreferrer"&gt;interceptors&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FilesInterceptor&lt;/code&gt; - identifica um &lt;em&gt;array&lt;/em&gt; de arquivos com o mesmo nome de campo do formulário;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FileFieldsInterceptor&lt;/code&gt; - &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AnyFilesInterceptor&lt;/code&gt; - &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. pegar o código do projeto anterior
&lt;/h3&gt;

&lt;p&gt;a nota de aula anterior é &lt;a href="https://dev.to/leonardominora/nest-upload-de-arquivo-5g1"&gt;NestJS - Upload de 1 arquivo&lt;/a&gt; que criou um projeto javascript para uma API Rest usando &lt;a href="https://nestjs.com/" rel="noopener noreferrer"&gt;nestjs&lt;/a&gt; e &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;typescript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;pode utilizar o seu próprio código, ou baixar o &lt;a href="https://github.com/infoweb-pos/2024-api-upload/archive/refs/tags/02-upload-arquivo-simples.zip" rel="noopener noreferrer"&gt;zip&lt;/a&gt; ou fazer o clone do repositório &lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Executar a API
&lt;/h3&gt;

&lt;p&gt;lembre de acessar a pasta do projeto!!!&lt;/p&gt;

&lt;p&gt;antes de executar a api, lembrar de instalar as bibliotecas do projeto com o comando &lt;code&gt;npm i&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;lançar a api em modo desenvolvimento executando o comando &lt;code&gt;npm&lt;/code&gt; com a opção &lt;code&gt;run&lt;/code&gt; para executar o script &lt;code&gt;start:dev&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api] &lt;span class="nv"&gt;$ &lt;/span&gt;npm run start:dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;a execução deverá produzir um resultado parecido com o console abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. criar e configurar 1 endpoint para receber vários arquivos
&lt;/h3&gt;

&lt;p&gt;adicionar um endpoint no &lt;em&gt;controller&lt;/em&gt; &lt;code&gt;src/upload/upload.controller.ts&lt;/code&gt;, atualizando as importações, conforme código (&lt;em&gt;diff&lt;/em&gt;) abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  Post,
  UploadedFile,
&lt;span class="gi"&gt;++  UploadedFiles,
&lt;/span&gt;  UseInterceptors,
} from '@nestjs/common';
&lt;span class="gd"&gt;--import { FileInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="gi"&gt;++import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
&lt;/span&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;&lt;span class="gi"&gt;++  ApiBadRequestResponse,
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { UploadService } from './upload.service';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('upload')
@ApiTags('upload')
&lt;span class="p"&gt;export class UploadController {
&lt;/span&gt;  constructor(private readonly uploadService: UploadService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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);
&lt;span class="err"&gt;
&lt;/span&gt;    return this.uploadService.responderInformacaoArquivo(arq);
  }
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;++  @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&amp;lt;Express.Multer.File&amp;gt;) {
++    return {
++      estado: 'ok',
++      data: {
++        quantidade: arquivos?.length,
++      },
++    };
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;foi adicionado nas importações o &lt;em&gt;interceptor&lt;/em&gt; &lt;code&gt;FilesInterceptor&lt;/code&gt; e o &lt;em&gt;decorator&lt;/em&gt; &lt;code&gt;UploadedFiles&lt;/code&gt; responsáveis por interceptar e extrair vários arquivos em uma &lt;em&gt;array&lt;/em&gt; nomeada como &lt;code&gt;arquivos&lt;/code&gt; no formulário.&lt;/p&gt;

&lt;p&gt;o &lt;em&gt;decorator&lt;/em&gt; &lt;code&gt;@Post&lt;/code&gt; configura o verdo &lt;code&gt;POST&lt;/code&gt; e o &lt;em&gt;path&lt;/em&gt; &lt;code&gt;arquivos&lt;/code&gt; do &lt;em&gt;endpoint&lt;/em&gt;.&lt;br&gt;
enquanto o &lt;em&gt;decorator&lt;/em&gt; &lt;code&gt;@UseInterceptors&lt;/code&gt; configura o uso do &lt;code&gt;FilesInterceptor&lt;/code&gt; para interceptar a requisitação HTTTP(S) a procura da variável &lt;code&gt;arquivos&lt;/code&gt; dentro do formulário no corpo da mensagem.&lt;/p&gt;

&lt;p&gt;as próximas linhas contém os &lt;em&gt;decorators&lt;/em&gt; &lt;code&gt;@Api&lt;/code&gt; (&lt;code&gt;ApiConsumes&lt;/code&gt;, &lt;code&gt;ApiBody&lt;/code&gt;, &lt;code&gt;ApiResponse&lt;/code&gt;, e &lt;code&gt;ApiBadRequestResponse&lt;/code&gt;) para configurar a documentação do &lt;a href="https://docs.nestjs.com/openapi/" rel="noopener noreferrer"&gt;swagger&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;a próxima linha, &lt;code&gt;uploadArquivos(@UploadedFiles() arquivos: Array&amp;lt;Express.Multer.File&amp;gt;)&lt;/code&gt; especifica o método &lt;code&gt;uploadArquivos&lt;/code&gt;.&lt;br&gt;
este método tem como parâmetro a variável &lt;code&gt;arquivos&lt;/code&gt; que irá receber um &lt;em&gt;array&lt;/em&gt; contendo itens cada tipados com &lt;code&gt;Express.Multer.File&lt;/code&gt;.&lt;br&gt;
o parâmetro &lt;code&gt;arquivos&lt;/code&gt; também esta decorado com &lt;code&gt;UploadedFiles&lt;/code&gt; que é responsável por extrair o &lt;em&gt;array&lt;/em&gt; de arquivos da mensagem HTTP.&lt;/p&gt;

&lt;p&gt;ao salvar, a api será relançada e o terminal onde ela esta sendo executada deverá ficar como o console abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[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

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para testar, use a documentação da api acessando o endereço &lt;a href="http://localhost:3000/docs/" rel="noopener noreferrer"&gt;http://localhost:3000/docs/&lt;/a&gt;&lt;br&gt;
clique no botão &lt;code&gt;Try it out&lt;/code&gt;, escolher alguns arquivos, e clicar em &lt;code&gt;Execute&lt;/code&gt;.&lt;br&gt;
a operação deve estar semelhante com a figura abaixo e o resultado após a execução com o json abaixo da figura.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0yhyheserazve76ga9lq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0yhyheserazve76ga9lq.png" alt="Image description" width="585" height="588"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estado"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. criar método no serviço para retornar as informações dos arquivos
&lt;/h3&gt;

&lt;p&gt;no arquivo &lt;code&gt;src/upload/upload.service.ts&lt;/code&gt; crie o método &lt;code&gt;responderInformacoesArquivos(arquivos: Array&amp;lt;Express.Multer.File&amp;gt;)&lt;/code&gt; e coloque a implementação conforme arquivo (diff) abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { Injectable } from '@nestjs/common';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Injectable()
&lt;span class="p"&gt;export class UploadService {
&lt;/span&gt;  responderInformacaoArquivo(arquivo: Express.Multer.File) {
    return {
      estado: 'ok',
      dados: {
        nome: arquivo.originalname,
        tamanho: arquivo.size,
        mimetype: arquivo.mimetype,
        encode: arquivo.encoding,
      },
    };
  }
&lt;span class="gi"&gt;++
++  responderInformacoesArquivos(arquivos: Array&amp;lt;Express.Multer.File&amp;gt;) {
++    const informacoes = arquivos.map((arquivo) =&amp;gt; {
++      return {
++        nome: arquivo.originalname,
++        tamanho: arquivo.size,
++        mimetype: arquivo.mimetype,
++        encode: arquivo.encoding,
++      };
++    });
++    return {
++      estado: 'ok',
++      dados: {
++        quantidade: arquivos?.length,
++        arquivos: informacoes,
++      },
++    };
++  }
&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;após a modificação do &lt;code&gt;service&lt;/code&gt; terá de modificar o &lt;code&gt;controller&lt;/code&gt; no arquivo &lt;code&gt;src/upload/upload.controller.ts&lt;/code&gt; conforme arquivo abaixo para chamar o método &lt;code&gt;responderInformacoesArquivos&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  Post,
  UploadedFile,
  UploadedFiles,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import {
&lt;/span&gt;  ApiBadRequestResponse,
  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="p"&gt;import { UploadService } from './upload.service';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('upload')
@ApiTags('upload')
&lt;span class="p"&gt;export class UploadController {
&lt;/span&gt;  constructor(private readonly uploadService: UploadService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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);
&lt;span class="err"&gt;
&lt;/span&gt;    return this.uploadService.responderInformacaoArquivo(arq);
  }
&lt;span class="err"&gt;
&lt;/span&gt;  @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&amp;lt;Express.Multer.File&amp;gt;) {
&lt;span class="gd"&gt;--    return {
--      estado: 'ok',
--      dados: {
--        quantidade: arquivos?.length,
--        arquivos: informacoes,
--      },
--    };
&lt;/span&gt;&lt;span class="gi"&gt;++    return this.uploadService.responderInformacoesArquivos(arquivos);
&lt;/span&gt;  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para testar, pode usar novamente a documentação da API conforme a figura anterior.&lt;br&gt;
o resultado agora será parecido conforme o &lt;code&gt;json&lt;/code&gt; abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estado"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dados"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arquivos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tamanho"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1373&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mimetype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text/markdown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"encode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7bit"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"package.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tamanho"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mimetype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"encode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7bit"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Captura de tela de 2024-09-15 15-35-33.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tamanho"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;44726&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mimetype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"encode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7bit"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Referência e link
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;notas de aula baseado nos tutoriais/documentações &lt;a href="https://docs.nestjs.com/" rel="noopener noreferrer"&gt;nestjs&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.nestjs.com/techniques/file-upload" rel="noopener noreferrer"&gt;File upload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nestjs.com/openapi/introduction" rel="noopener noreferrer"&gt;OpenAPI - Introduction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>infoweb</category>
      <category>nestjs</category>
      <category>upload</category>
      <category>typescript</category>
    </item>
    <item>
      <title>NestJS - criar endpoint para upload de 1 arquivo</title>
      <dc:creator>Leonardo Minora</dc:creator>
      <pubDate>Mon, 09 Sep 2024 20:57:32 +0000</pubDate>
      <link>https://dev.to/leonardominora/nest-upload-de-arquivo-5g1</link>
      <guid>https://dev.to/leonardominora/nest-upload-de-arquivo-5g1</guid>
      <description>&lt;h2&gt;
  
  
  Informações gerais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;aula introdutória de &lt;strong&gt;endpoint para upload de arquivo&lt;/strong&gt; para os &lt;strong&gt;alunos de programação orientada a serviços&lt;/strong&gt;, do 4o ano de infoweb, do CNAT-IFRN&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/infoweb-pos/2024-api-upload/" rel="noopener noreferrer"&gt;repositório de código&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;código final &lt;a href="https://github.com/infoweb-pos/2024-api-upload/archive/refs/tags/02-upload-arquivo-simples.zip" rel="noopener noreferrer"&gt;zip&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  objetivo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;criar 1 endpoint para API de upload de arquivo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  notas de aula
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;criar um projeto nestjs e instalar a lib necessária&lt;/li&gt;
&lt;li&gt;executar (levantar) a api&lt;/li&gt;
&lt;li&gt;configurar a API para documentar com swagger&lt;/li&gt;
&lt;li&gt;criar módulo nestjs para upload&lt;/li&gt;
&lt;li&gt;programar endpoint para upload de 1 arquivo&lt;/li&gt;
&lt;li&gt;Programar o serviço para processar e responder ao endpoint de upload&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. criar um projeto nestjs e instalar a lib necessária
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;## cria novo projeto nestjs&lt;/span&gt;
npx @nestjs/cli &lt;span class="nt"&gt;--package-manager&lt;/span&gt; npm new upload-api

&lt;span class="c"&gt;## após criado o projeto, e em tudo terminando ok&lt;/span&gt;
&lt;span class="c"&gt;## acessa a pasta do projeto nestjs&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;upload-api

&lt;span class="c"&gt;## instala a lib em modo desenvolvimento&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; @types/multer

npm &lt;span class="nb"&gt;install&lt;/span&gt; @nestjs/swagger

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o resultado deve parecer com o terminal abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npx @nestjs/cli &lt;span class="nt"&gt;--package-manager&lt;/span&gt; npm new upload-api
&lt;span class="go"&gt;⚡  We will scaffold your app in a few seconds..

CREATE upload-api/.eslintrc.js (663 bytes)
CREATE upload-api/.prettierrc (51 bytes)
CREATE upload-api/README.md (3340 bytes)
CREATE upload-api/nest-cli.json (171 bytes)
CREATE upload-api/package.json (1955 bytes)
CREATE upload-api/tsconfig.build.json (97 bytes)
CREATE upload-api/tsconfig.json (546 bytes)
CREATE upload-api/src/app.controller.spec.ts (617 bytes)
CREATE upload-api/src/app.controller.ts (274 bytes)
CREATE upload-api/src/app.module.ts (249 bytes)
CREATE upload-api/src/app.service.ts (142 bytes)
CREATE upload-api/src/main.ts (208 bytes)
CREATE upload-api/test/app.e2e-spec.ts (630 bytes)
CREATE upload-api/test/jest-e2e.json (183 bytes)

✔ Installation in progress... ☕

🚀  Successfully created project upload-api
👉  Get started with the following commands:

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;upload-api
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npm run start:dev
&lt;span class="go"&gt;

                          Thanks for installing Nest 🙏
                 Please consider donating to our open collective
                        to help us maintain this package.


               🍷  Donate: https://opencollective.com/nest

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;upload-api
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;[upload-api]$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @types/multer
&lt;span class="go"&gt;
added 1 package, and audited 687 packages in 2s

106 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

&lt;/span&gt;&lt;span class="gp"&gt;[upload-api]$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. executar (levantar) a api
&lt;/h3&gt;

&lt;p&gt;levantar a api em modo de desenvolvimento para que no momento que houver mudança nos códigos-fonte, a API ser re-lançada.&lt;/p&gt;

&lt;p&gt;executar a ferramenta &lt;code&gt;npm&lt;/code&gt; com o comando &lt;code&gt;run&lt;/code&gt; para executar o script &lt;code&gt;start:dev&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api]&lt;span class="nv"&gt;$ &lt;/span&gt;npm run start:dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;resultado do comando acima deve ser algo parecido com o terminal abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[15:31:39] Starting compilation in watch mode...

[15:31:41] Found 0 errors. Watching for file changes.

[Nest] 620648  - 07/09/2024, 15:31:41     LOG [NestFactory] Starting Nest application...
[Nest] 620648  - 07/09/2024, 15:31:41     LOG [InstanceLoader] AppModule dependencies initialized +13ms
[Nest] 620648  - 07/09/2024, 15:31:41     LOG [RoutesResolver] AppController {/}: +5ms
[Nest] 620648  - 07/09/2024, 15:31:41     LOG [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 620648  - 07/09/2024, 15:31:41     LOG [NestApplication] Nest application successfully started +2ms

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. configurar a API para documentar com swagger
&lt;/h3&gt;

&lt;p&gt;editar o arquivo &lt;code&gt;/src/main.ts&lt;/code&gt; para colocar a configuração do swagger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
&lt;/span&gt;&lt;span class="gi"&gt;++import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;async function bootstrap() {
&lt;/span&gt;  const app = await NestFactory.create(AppModule);
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;++  const config = new DocumentBuilder()
++    .setTitle('Infoweb - Upload API')
++    .setDescription('API exemplo de upload de arquivos')
++    .setVersion('1.0')
++    .build();
++  const document = SwaggerModule.createDocument(app, config);
++  SwaggerModule.setup('docs', app, document);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  await app.listen(3000);
}
&lt;span class="p"&gt;bootstrap();
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DocumentBuilder&lt;/code&gt; é responsável por configurar a documentação da API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SwaggerModule.createDocument&lt;/code&gt; é responsável por construir a documentação.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SwaggerModule.setup&lt;/code&gt; cria um endpoint no &lt;code&gt;app&lt;/code&gt; e vincula a documentação da API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. criar módulo nestjs para upload
&lt;/h3&gt;

&lt;p&gt;abrir um 2o terminal, e executar o &lt;code&gt;@nestjs/cli&lt;/code&gt; com o comando &lt;code&gt;generate resource&lt;/code&gt;, podendo abreviar &lt;code&gt;g res&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;upload-api]&lt;span class="nv"&gt;$ &lt;/span&gt;npx @nestjs/cli generate resource upload &lt;span class="nt"&gt;--no-spec&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o resultado do comando deverá parecer com o terminal abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;[upload-api]$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npx @nestjs/cli generate resource upload &lt;span class="nt"&gt;--no-spec&lt;/span&gt;
&lt;span class="go"&gt;? What transport layer do you use? REST API
? Would you like to generate CRUD entry points? No
CREATE src/upload.controller.ts (216 bytes)
CREATE src/upload.module.ts (255 bytes)
CREATE src/upload.service.ts (90 bytes)
UPDATE package.json (2020 bytes)
UPDATE src/app.module.ts (309 bytes)
✔ Packages installed successfully.

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ao final, o terminal que esta executando a API deve adicionar a rota &lt;code&gt;/upload&lt;/code&gt; como &lt;code&gt;[RoutesResolver]&lt;/code&gt;, ver terminal abaixo como exemplo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[09:45:33] File change detected. Starting incremental compilation...

[09:45:33] Found 0 errors. Watching for file changes.

[Nest] 14414  - 13/09/2024, 09:45:35     LOG [NestFactory] Starting Nest application...
[Nest] 14414  - 13/09/2024, 09:45:35     LOG [InstanceLoader] AppModule dependencies initialized +12ms
[Nest] 14414  - 13/09/2024, 09:45:35     LOG [InstanceLoader] UploadModule dependencies initialized +1ms
[Nest] 14414  - 13/09/2024, 09:45:35     LOG [RoutesResolver] AppController {/}: +170ms
[Nest] 14414  - 13/09/2024, 09:45:36     LOG [RouterExplorer] Mapped {/, GET} route +20ms
[Nest] 14414  - 13/09/2024, 09:45:36     LOG [RoutesResolver] UploadController {/upload}: +9ms
[Nest] 14414  - 13/09/2024, 09:45:36     LOG [NestApplication] Nest application successfully started +32ms

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. programar endpoint para upload de 1 arquivo
&lt;/h3&gt;

&lt;p&gt;para fazer o upload de um único arquivo no endpoint de uma API usando nestjs, preciso vincular o &lt;a href="https://docs.nestjs.com/interceptors" rel="noopener noreferrer"&gt;interceptor&lt;/a&gt; &lt;code&gt;FileInterceptor()&lt;/code&gt; ao endpoint e extrair esse arquivo da requisição usando o decorador @UploadedFile().&lt;/p&gt;

&lt;p&gt;editar o arquivo &lt;code&gt;src/uplaod/upload.controller.ts&lt;/code&gt; para inserir os códigos abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gi"&gt;++import {
++  Controller,
++  Post,
++  UploadedFile,
++  UseInterceptors,
++} from '@nestjs/common';
&lt;/span&gt;&lt;span class="p"&gt;import { UploadService } from './upload.service';
&lt;/span&gt;&lt;span class="gi"&gt;++import { FileInterceptor } from '@nestjs/platform-express';
++import {
++  ApiBody,
++  ApiConsumes,
++  ApiOperation,
++  ApiResponse,
++  ApiTags,
++} from '@nestjs/swagger';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;@Controller('upload')
&lt;span class="gi"&gt;++@ApiTags('upload')
&lt;/span&gt;&lt;span class="p"&gt;export class UploadController {
&lt;/span&gt;  constructor(private readonly uploadService: UploadService) {}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;++  @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 {
++      estado: 'ok',
++    };
++  }
&lt;/span&gt;}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;os &lt;em&gt;decorators&lt;/em&gt; novos são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;swagger

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@ApiTags&lt;/code&gt; cria uma divisão na documentação da API organizada pela string passada como parâmetro.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@ApiConsumes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ApiBody&lt;/code&gt; configura o que capturar do corpo da mensagem de requisição&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ApiOperation&lt;/code&gt; configura como será descrito o endpoint na documentação&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ApiResponse&lt;/code&gt; configura as respostas na documentação&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;nestjs

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@UseInterceptors&lt;/code&gt; usa um &lt;a href="https://docs.nestjs.com/interceptors" rel="noopener noreferrer"&gt;interceptors&lt;/a&gt; que tem a função de interceptar as requisições antes que ela chegue na função que trata o endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@UploadedFile&lt;/code&gt; trabalha em conjunto com &lt;a href="https://docs.nestjs.com/interceptors" rel="noopener noreferrer"&gt;interceptor&lt;/a&gt; para extração do arquivo da mensagem de requisição.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;FileInterceptor&lt;/code&gt; é um &lt;a href="https://docs.nestjs.com/interceptors" rel="noopener noreferrer"&gt;interceptor&lt;/a&gt; padrão do nestjs para extrair um arquivo da mensagem de requisição. Este &lt;a href="https://docs.nestjs.com/interceptors" rel="noopener noreferrer"&gt;interceptor&lt;/a&gt; trabalha junto do decorator &lt;code&gt;@UploadedFile&lt;/code&gt;. É definido aqui o nome do campo do formulário que referencia o arquivo.&lt;/p&gt;

&lt;p&gt;o console onde executa a API deve parecer como o terminal abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[10:14:23] File change detected. Starting incremental compilation...

[10:14:23] Found 0 errors. Watching for file changes.

[Nest] 23723  - 13/09/2024, 10:14:23     LOG [NestFactory] Starting Nest application...
[Nest] 23723  - 13/09/2024, 10:14:23     LOG [InstanceLoader] AppModule dependencies initialized +11ms
[Nest] 23723  - 13/09/2024, 10:14:23     LOG [InstanceLoader] UploadModule dependencies initialized +0ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RoutesResolver] AppController {/}: +13ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RouterExplorer] Mapped {/, GET} route +3ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RoutesResolver] UploadController {/upload}: +0ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [NestApplication] Nest application successfully started +1ms

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para testar o endpoint, acessar o link &lt;a href="http://localhost:3000/docs" rel="noopener noreferrer"&gt;http://localhost:3000/docs&lt;/a&gt;, ir em &lt;code&gt;/upload/exemplo-simples&lt;/code&gt;, clicar no botão &lt;code&gt;try it out&lt;/code&gt;, escolher um arquivo e executar a requisição.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9dn8aisx3z0dwz5z6i0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9dn8aisx3z0dwz5z6i0.png" alt="teste do endpoint de upload com o swagger" width="673" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;após a execução do teste, o terminal ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[10:14:23] File change detected. Starting incremental compilation...

[10:14:23] Found 0 errors. Watching for file changes.

[Nest] 23723  - 13/09/2024, 10:14:23     LOG [NestFactory] Starting Nest application...
[Nest] 23723  - 13/09/2024, 10:14:23     LOG [InstanceLoader] AppModule dependencies initialized +11ms
[Nest] 23723  - 13/09/2024, 10:14:23     LOG [InstanceLoader] UploadModule dependencies initialized +0ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RoutesResolver] AppController {/}: +13ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RouterExplorer] Mapped {/, GET} route +3ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RoutesResolver] UploadController {/upload}: +0ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [RouterExplorer] Mapped {/upload/exemplo-simples, POST} route +1ms
[Nest] 23723  - 13/09/2024, 10:14:24     LOG [NestApplication] Nest application successfully started +1ms
{
  fieldname: 'arquivo',
  originalname: 'README.md',
  encoding: '7bit',
  mimetype: 'text/markdown',
&lt;/span&gt;&lt;span class="gp"&gt;  buffer: &amp;lt;Buffer 23 20 4e 65 73 74 4a 53 20 2d 20 55 70 6c 6f 61 64 20 64 65 20 61 72 71 75 69 76 6f 73 0a 0a 0a 23 23 20 49 6e 66 6f 72 6d 61 c3 a7 c3 b5 65 73 20 67 ... 958 more bytes&amp;gt;&lt;/span&gt;,
&lt;span class="go"&gt;  size: 1008
}

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Programar o serviço para processar e responder ao endpoint de upload
&lt;/h3&gt;

&lt;p&gt;editar o arquivo &lt;code&gt;src/uplaod/upload.service.ts&lt;/code&gt; para inserir os códigos abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UploadService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;responderInformacaoArquivo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arquivo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Multer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;estado&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;dados&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tamanho&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;mimetype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mimetype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arquivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;também deve modificar o arquivo &lt;code&gt;src/uplaod/upload.controller.ts&lt;/code&gt; para inserir os códigos abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import {
&lt;/span&gt;  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
} from '@nestjs/common';
&lt;span class="p"&gt;import { UploadService } from './upload.service';
import { FileInterceptor } from '@nestjs/platform-express';
import {
&lt;/span&gt;  ApiBody,
  ApiConsumes,
  ApiOperation,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
&lt;span class="err"&gt;
&lt;/span&gt;@Controller('upload')
@ApiTags('upload')
&lt;span class="p"&gt;export class UploadController {
&lt;/span&gt;  constructor(private readonly uploadService: UploadService) {}
&lt;span class="err"&gt;
&lt;/span&gt;  @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);
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;--    return {
--      estado: 'ok',
--    };
&lt;/span&gt;&lt;span class="gi"&gt;++    return this.uploadService.responderInformacaoArquivo(arq);
&lt;/span&gt;  }
}
&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;novamente para testar o endpoint, acessar o link &lt;a href="http://localhost:3000/docs" rel="noopener noreferrer"&gt;http://localhost:3000/docs&lt;/a&gt;, ir em &lt;code&gt;/upload/exemplo-simples&lt;/code&gt;, clicar no botão &lt;code&gt;try it out&lt;/code&gt;, escolher um arquivo e executar a requisição.&lt;br&gt;
perceba a mudança com a resposta da requisição que deverá parecer com algo como o json abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"estado"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dados"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"nome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tamanho"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mimetype"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text/markdown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"encode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7bit"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Referência e link
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;notas de aula baseado nos tutoriais/documentações &lt;a href="https://docs.nestjs.com/" rel="noopener noreferrer"&gt;nestjs&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.nestjs.com/techniques/file-upload" rel="noopener noreferrer"&gt;File upload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.nestjs.com/openapi/introduction" rel="noopener noreferrer"&gt;OpenAPI - Introduction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>infoweb</category>
      <category>nestjs</category>
      <category>upload</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
