Como baixar um arquivo através do download do navegador? Utilizando nodejs

Como baixar um arquivo através do download do navegador? Utilizando nodejs

Possuo um endpoint que já funciona e retorna JSON. É um endpoint que retorna uma lista de itens, e desejo que quando o usuário chamar o endpoint o navegador execute a ação padrão de fazer o download, e consequentemente salve o arquivo no diretório configurado como padrão para baixar.

Esse é o fluxo que desejo implementar, desta forma, vamos mostrar através de um exemplo concreto como programar esta funcionalidade.

Do ponto de vista de implementação tudo isso pode ser conseguido através de mudanças no backend.

Vamos então para a estrutura de dados:

[{
    "id" : "f7379ae8-8f9b-4cd5-8221-51efe19e721b",
    "apelido" : "josé",
    "nome" : "José Roberto",
    "nascimento" : "2000-10-01",
    "stack" : ["C#", "Node", "Oracle"]
},
{
    "id" : "5ce4668c-4710-4cfb-ae5f-38988d6d49cb",
    "apelido" : "ana",
    "nome" : "Ana Barbosa",
    "nascimento" : "1985-09-23",
    "stack" : ["Node", "Postgres"]
}]

Em nosso serviço, temos um array composto por umusuario que foi definida na rinha de backend.

Temos agora uma abstração de um usuário. Dessa forma vamos implementar um endpoint para recuperar estas informações. Segue a definição do serviço, que é uma aplicação em nodejs que utiliza o express (estou supondo que já possui uma configuração inicial de um projeto express, esta tarefa é trivial mas se quer um exemplo que mostra como fazer a configuração inicial, pode ler esta postagem):

const express = require('express')
const app = express()
app.use(express.json())

app.get('/usuarios', (req, res) => {
    const usuarios = [{
        "id" : "f7379ae8-8f9b-4cd5-8221-51efe19e721b",
        "apelido" : "josé",
        "nome" : "José Roberto",
        "nascimento" : "2000-10-01",
        "stack" : ["C#", "Node", "Oracle"]
    },
    {
        "id" : "5ce4668c-4710-4cfb-ae5f-38988d6d49cb",
        "apelido" : "ana",
        "nome" : "Ana Barbosa",
        "nascimento" : "1985-09-23",
        "stack" : ["Node", "Postgres"]
    }];
    res.status(200).json(usuarios)
})

Já temos um serviço com uma rota que retorna todos os usuários.

Criando uma rota que retorna um arquivo para download JSON

Já temos a rota que retorna os dados que desejamos que é a rota /usuarios. Agora é só fazer o envio destes mesmos dados no formato json.

Para isso vamos apenas adicionar o header Content-Type com os valores application/json e adicionar o header 'Content-Disposition com o valor 'attachment; filename=test.json'

Esse header é o que vai realmente fazer a mágica acontecer.

Dessa forma criarei uma nova rota /usuarios/download que contém essa implementação:

app.get('/usuarios/download', (req, res) => {
        const usuarios = [{
            "id" : "f7379ae8-8f9b-4cd5-8221-51efe19e721b",
            "apelido" : "josé",
            "nome" : "José Roberto",
            "nascimento" : "2000-10-01",
            "stack" : ["C#", "Node", "Oracle"]
        },
        {
            "id" : "5ce4668c-4710-4cfb-ae5f-38988d6d49cb",
            "apelido" : "ana",
            "nome" : "Ana Barbosa",
            "nascimento" : "1985-09-23",
            "stack" : ["Node", "Postgres"]
        }];
        res.setHeader('Content-Disposition', 'attachment; filename=test.json');
        res.status(200).send(usuarios).end()
    })

Repare que aqui o nome do arquivo é test.json (você pode substituir pelo nome que desejar, desde que sigam as restrições definidas na RFC 6266, que versa sobre o campo header Content-Disposition).

Outra maneira de implementar esta mesma funcionalidade é usar a função helper implementada pelo express download. Segue um exemplo de como podemos utilizar a função download.

const fs = require('fs');
//...
app.get('/usuarios/download', (req, res) => {
    const usuarios = [{
        "id" : "f7379ae8-8f9b-4cd5-8221-51efe19e721b",
        "apelido" : "josé",
        "nome" : "José Roberto",
        "nascimento" : "2000-10-01",
        "stack" : ["C#", "Node", "Oracle"]
    },
    {
        "id" : "5ce4668c-4710-4cfb-ae5f-38988d6d49cb",
        "apelido" : "ana",
        "nome" : "Ana Barbosa",
        "nascimento" : "1985-09-23",
        "stack" : ["Node", "Postgres"]
    }];
    fs.writeFileSync('data.json', usuarios);
    res.download('data.json', 'test.json');
});

Veja que nesse exemplo foi necessário utilizar a função fs que manipula arquivos. Dessa forma vamos escrever no sistema de arquivos um arquivo que possui o nome data.json e após escrever o conteúdo da variável usuario neste arquivo, fazemos o envio deste arquivo para o cliente, através da chamada da função download. A definição do serviço completo pode ser visto aqui.

Obrigado