Como lidar com uploads de arquivos no Node.js com Fastify
Amarachi Aso
8 de dezembro de 2022
0 minutos de leituraO upload de arquivos é uma funcionalidade bastante comum em aplicações web. Por isso, muitos frameworks web oferecem maneiras de permitir que aplicações no servidor recebam arquivos e trabalhem com eles. Isso também vale para o Fastify, um framework web para Node.js frequentemente considerado sucessor do Express. Ele é rápido e tem como foco oferecer a melhor experiência para desenvolvedores, com uma arquitetura de plugins poderosa e o mínimo de sobrecarga possível.
Neste tutorial, você vai usar o framework Fastify em uma aplicação Node.js para configurar o upload de arquivos. Você vai aprender como os uploads funcionam em um servidor comum e como lidar com eles em uma aplicação de servidor Fastify.
Noções básicas sobre upload de arquivos
Para fazer upload de arquivos para um servidor de aplicações, o computador cliente precisa enviar uma requisição POST ao servidor. No corpo da requisição, ele envia dados normalmente enviados por formulários HTML. Os formulários HTML oferecem três métodos de codificação de dados:
application/x-www-form-urlencoded(padrão) é o tipo de conteúdo ou método de codificação padrão para formulários HTML. No entanto, quando os formulários incluem arquivos, é preciso usar o métodomultipart/form-data.multipart/form-datarepresenta as várias partes ou campos de um formulário HTML, enviando as partes como pares nome/valor no corpo da requisição. O nome e o valor de cada par correspondem, respectivamente, ao nome e ao valor dos campos de entrada.text/plainé usado para enviar dados como texto simples, sem formatação, e não pode ser usado para enviar arquivos.
Quando arquivos são enviados a um servidor de aplicações, geralmente é para que o servidor os processe, salve ou faça as duas coisas. As aplicações no servidor podem processar e salvar arquivos enviados de várias maneiras, incluindo:
Salvá-los no sistema de arquivos do próprio servidor. Isso pode ser feito em um diretório dedicado no mesmo servidor em que a aplicação está em execução ou em outro servidor dedicado ao armazenamento de arquivos.
Armazená-los em um banco de dados.
Enviar os arquivos para um serviço de armazenamento em nuvem, como Amazon S3 ou Cloudinary.
Este tutorial se concentra no uso do primeiro método para lidar com uploads de arquivos.
Como implementar o upload de arquivos com Fastify
Antes de começar este tutorial, você vai precisar de:
Node.js instalado
Um editor de código de sua preferência, como o Visual Studio Code (VS Code)
Postman: você pode fazer login e usar o aplicativo web ou instalá-lo no computador.
Nas próximas seções, você vai criar um projeto Fastify, configurar um plugin de upload de arquivos, criar uma rota /upload capaz de lidar com uploads de vários arquivos e escrever um caso de teste para essa rota.
Crie um projeto e configure o Fastify
Para começar, crie um projeto e configure o Fastify. Acesse o diretório em que deseja criar o projeto e crie uma pasta chamada fastify-file-upload. No terminal, execute o seguinte comando:
Acesse essa pasta:
Em seguida, abra a pasta no editor de código de sua preferência. Se estiver usando o VS Code, você pode executar o seguinte comando:
Inicialize o projeto e crie um arquivo package.json executando:
Em seguida, instale as dependências que você vai usar neste projeto:
E crie dois arquivos: app.js e server.js:
O arquivo app.js vai conter o código da aplicação. Copie e cole nele o seguinte código:
import Fastify from fastify
Esse código importa o framework Fastify e cria uma instância de aplicação com ele. Em seguida, adicione o código abaixo ao arquivo server.js:
Esse código inicia a aplicação quando ela é executada ou retorna um erro caso ocorra algum problema ao iniciá-la.
Neste projeto, você vai usar a sintaxe de módulos ES6. Portanto, seus arquivos JavaScript precisam ser carregados como módulos. Para isso, adicione a propriedade type ao arquivo package.json e defina o valor como module:
Configure um plugin de upload de arquivos
O Fastify-multipart oferece suporte a tipos de conteúdo multipart no Fastify. Como você já instalou o plugin junto com as dependências, agora é hora de configurá-lo. Para isso, importe multipart de '@fastify/multipart' e registre-o.
Adicione ao arquivo app.js as linhas que começam com +:
Aqui, você registrou o multipart na aplicação Fastify criada anteriormente. Agora, a instância da aplicação pode analisar facilmente tipos de conteúdo multipart.
Uploads de arquivos
Há várias maneiras de acessar os arquivos de uma requisição POST. Por exemplo, se você sabe que uma requisição contém apenas um arquivo, pode acessá-lo com o seguinte código:
Neste código, request é o parâmetro da requisição recebido pela função de tratamento da rota de upload, cuja função de tratamento se parece com esta:
Se você espera vários arquivos, basta chamar o método files() em vez de file(), assim:
No arquivo app.js, você precisa escrever o código para implementar completamente o upload de vários arquivos. Mas, primeiro, crie um diretório para armazenar os arquivos enviados à aplicação. Crie esse diretório na raiz do projeto e dê a ele o nome uploads:
Depois, faça as seguintes alterações no arquivo app.js:
No código atualizado, você importou funções dos módulos principais do Node.js fs, util e stream. Em seguida, criou uma rota /upload e sua função de tratamento.
Dentro da função de tratamento, você usou req.files() para acessar todos os arquivos da requisição. Você percorreu os arquivos e, para cada um, o código await pump(part.file, fs.createWriteStream(`./uploads/${part.filename}`)) faz o upload e o salva no diretório de uploads criado anteriormente.
Observe que os arquivos enviados não ficam acumulados na memória antes de serem salvos. Em vez disso, a função fs.createWriteStream cria um fluxo no destino, enquanto o fluxo de arquivo proveniente de part.file é direcionado para o novo fluxo. Assim, o conteúdo do arquivo não é armazenado primeiro na memória; os dados são gravados diretamente no arquivo em blocos, à medida que passam pelo fluxo. Isso é especialmente útil para enviar arquivos grandes. Esse método não bloqueia o loop de eventos e também é eficiente no uso de memória para lidar com arquivos na aplicação.
Agora é hora de iniciar o servidor e enviar arquivos para ele usando o Postman. No arquivo package.json, substitua o script de inicialização pelo seguinte:
Em seguida, inicie o servidor com:
Acesse o Postman e envie uma requisição POST para http://localhost:8000/upload. No corpo da requisição, selecione a opção form-data e envie dois arquivos de sua escolha:

Neste exemplo, você envia um arquivo chamado article.txt e outro chamado cover.jpg (as respectivas chaves serão "article" e "coverImage"). Depois de enviar os arquivos, você deverá receber o código de status 200 e o objeto de retorno {message : 'files uploaded' }:

Você também deverá ver os arquivos adicionados ao diretório "upload" criado anteriormente para armazenar os arquivos enviados.
Neste ponto, você já sabe lidar com uploads de vários arquivos usando o plugin fastify/multipart. A maioria dos formulários exige o envio não apenas de arquivos, mas também de arquivos e outros campos de texto. Para lidar com formulários desse tipo, modifique o código existente para processar tanto os fluxos de arquivos quanto os outros campos.
Para isso, faça as seguintes alterações no arquivo app.js:
Observe que, desta vez, você usa req.parts() para acessar tanto os fluxos de arquivos quanto os campos, em vez de req.files(). No corpo do loop, você usa uma instrução if para identificar quais partes são arquivos e tratá-las de maneira diferente dos campos.
Agora é hora de fazer outra requisição. Salve o arquivo, pare e reinicie o servidor com npm start. Volte ao Postman, exclua os pares de chave/valor da requisição anterior e crie novos. No primeiro campo, informe seu nome completo e, em seguida, adicione dois arquivos quaisquer, como antes.
Observação: Se você pretende usar os mesmos arquivos, talvez queira excluir do diretório de uploads aqueles que enviou anteriormente.
Sua requisição deverá ficar assim:

Se estiver tudo certo, sua aplicação agora poderá lidar com vários fluxos de arquivos e campos.
Escreva casos de teste
Para proteger sua implementação de upload de arquivos, você precisa escrever testes. Mas como testar uploads de arquivos no Fastify? Neste exemplo, você vai usar o framework de testes tap, o pacote form-auto-content e o método .inject do Fastify para escrever os casos de teste.
Crie o arquivo app.test.js na raiz do projeto. Em seguida, copie e cole nele o seguinte código:
Substitua os caminhos ./sample_files/file.txt e ./sample_files/cover.jpg pelos caminhos de dois arquivos quaisquer do seu sistema. Ou você pode copiar estes arquivos aqui.
O método .inject do Fastify permite injetar requisições HTTP simuladas na aplicação sem executar o código em um servidor real. No código anterior, observe como você usou formAutoContent para criar um formulário chamado myForm e depois usou esse formulário como corpo da requisição POST simulada dentro do caso de teste. Há apenas um caso de teste, que espera que, ao enviar um formulário com vários arquivos, a aplicação retorne um statusCode igual a 200.
Execute o teste e confirme que ele foi aprovado. No arquivo package.json, substitua o script de teste por este:
Em seguida, execute:
O teste deverá passar e a saída deverá ficar assim:

Todo o código deste tutorial está disponível neste repositório no GitHub.
Conclusão
Neste artigo, você aprendeu o básico sobre upload de arquivos e por que formulários com arquivos só são codificados usando o multipart/form-data content-type. Você também aprendeu que aplicações no servidor podem processar e salvar arquivos de duas maneiras: em um diretório dedicado no mesmo servidor ou em um serviço de armazenamento em nuvem, como Amazon S3. Por fim, aprendeu a lidar com uploads no Fastify, um framework web rápido e com pouca sobrecarga para Node.js.
Se quiser saber mais, consulte a documentação do plugin Fastify-multipart e o guia do Fastify sobre testes.



