encurtadores de URL como bit.ly e cutt.ly são incrivelmente populares. Neste artigo, vamos criar uma ferramenta semelhante, construindo um serviço de API que encurta os URLs fornecidos a ela.

Demonstração Of Get Request URL Shortener API Service

Para o projeto, usaremos MongoDB e Node.js , então você deve ter conhecimento básico deles para este tutorial.

Planejando o processo de construção do encurtador de URL em Node.js

Vamos primeiro planejar o processo de construção, que é bastante simples. Para cada URL passado em nossa API, geraremos um ID exclusivo e criaremos um URL curto com ele. Em seguida, o URL longo, o URL curto e a ID exclusiva serão armazenados no banco de dados.

Quando um usuário envia uma solicitação GET para o URL curto, o URL será pesquisado no banco de dados e o usuário será redirecionado para o URL original correspondente. Complexo de som? Não se preocupe, vamos cobrir tudo o que você precisa saber.

Inicializando o aplicativo e instalando dependências com MongoDB

Primeiro, vamos precisar de um banco de dados. Como usaremos o MongoDB, precisaremos de um URI SRV do MongoDB. Você pode criar um banco de dados a partir deste link . Nossa próxima etapa é inicializar a pasta do projeto com o NPM.

Vamos usar o comando npm init no diretório do projeto para inicializar. Assim que o projeto for inicializado, iremos instalar as dependências necessárias. As dependências de que precisamos são:

  • dotenv : este pacote carrega as variáveis ​​de ambiente de um arquivo chamado .env para process.env
  • express : esta é uma estrutura de aplicativo da web mínima e flexível para Node.js
  • mongoose : esta é uma ferramenta de modelagem de objetos MongoDB para Node.js
  • shortid : este pacote nos permite gerar os IDs curtos para nossos URLs

A única dependência do desenvolvedor de que precisamos é nodemon . Uma ferramenta nodemon é uma ferramenta simples que reinicia automaticamente o servidor Node.js quando ocorre uma alteração no arquivo.

Agora, vamos instalar as dependências. Para instalar as dependências que precisaremos em nosso aplicativo, usaremos o comando npm i dotenv express mongoose shortid e depois que as dependências forem instaladas, instalaremos a dependência do desenvolvedor com npm i-D nodemon .

Vamos criar nosso servidor em nosso arquivo app.js usando Express. Para configurar um servidor Express, precisamos importar o pacote Express para o arquivo app.js . Assim que o pacote for importado, inicialize-o e armazene-o em uma variável chamada app .

Agora, use a função listen disponível para criar o servidor. Aqui está um exemplo.

 const Express=require ('Express');
const app=Express (); //Configuração do servidor
const PORT=3333;
app.listen (PORTA, ()=> { console.log (`Servidor está rodando em PORT $ {PORT}`);
});

Usei a porta 3333 para executar o servidor. O método listen no Express inicia um soquete UNIX e escuta uma conexão em uma determinada porta.

Agora, crie um arquivo .env dentro da pasta config para armazenar o URI SRV do MongoDB e a URL base. A URL base será o local do servidor host local por enquanto. Este é o código do meu arquivo .env :

 MONGO_URI=mongodb + srv://nemo: [email protected]/myFirstDatabase? retryWrites=true & w=majoritário
BASE=http://localhost: 3333

Lembre-se de alterar o campo no URI do MongoDB com a senha do seu banco de dados.

Conectando o banco de dados ao aplicativo

Agora, conectaremos o banco de dados ao aplicativo. Para fazer isso, importe as dependências mongoose e dotenv em seu arquivo db.js , que está dentro do config pasta.

 const mongoose=require ('mongoose');
require ('dotenv'). config ({path:'./.env'});

A chave do objeto path é passada dentro da configuração dotenv porque o arquivo .env não está localizado no diretório raiz. Estamos passando a localização do arquivo .env por meio dele.

Agora crie uma função assíncrona chamada connectDB dentro de um arquivo chamado db.js , dentro da pasta config . Usarei async/await para este artigo.

 const connectDB=async ()=> { tentar { aguarde mongoose.connect (process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, }); console.log ('banco de dados conectado'); } catch (errar) { console.error (err.message); process.exit (1); }
}; module.exports=connectDB;

No bloco try , esperamos que mongoose se conecte com o URI do MongoDB fornecido. O primeiro parâmetro no método mongoose.connect é o URI SRV do MongoDB. Observe que os dois pares de valores-chave são passados ​​no segundo parâmetro para remover os avisos do console. Vamos entender o que significam os dois parâmetros de valor-chave.

  • useNewUrlParser: true : o driver MongoDB subjacente tornou o analisador de string de conexão atual obsoleto. É por isso que ele adicionou uma nova bandeira. Se a conexão encontrar qualquer problema com o novo analisador de string, ele pode voltar para o antigo
  • useUnifiedTopology: true : é definido como false por padrão. Aqui, ele é definido como true para que o novo mecanismo de gerenciamento de conexão do driver MongoDB possa ser usado

Se ocorrer algum erro dentro da instrução catch , nós registraremos o erro no console e sairemos com process.exit (1) . Por fim, exportamos a função com module.exports .

Agora, importe o arquivo db.js para o arquivo app.js com const connectDB=require ('./config/db'); e chame a função connectDB com connectDB () .

Criação do esquema mongoose no MongoDB

Usaremos um esquema mongoose para determinar como os dados são armazenados no MongoDB. Essencialmente, o esquema mongoose é um modelo para os dados. Vamos criar um arquivo chamado Url.js dentro de uma pasta models . Importe mongoose aqui e, em seguida, use o construtor mongoose.Schema para criar o esquema.

 const mongoose=require ('mongoose'); const UrlSchema=new mongoose.Schema ({ urlId: { tipo: String, obrigatório: verdadeiro, }, origUrl: { tipo: String, obrigatório: verdadeiro, }, shortUrl: { tipo: String, obrigatório: verdadeiro, }, cliques: { tipo: número, obrigatório: verdadeiro, padrão: 0, }, data: { tipo: String, padrão: Date.now, },
}); module.exports=mongoose.model ('Url', UrlSchema);

As chaves do objeto pai são as chaves que serão armazenadas no banco de dados. Nós definimos cada chave de dados. Observe que há um campo obrigatório para alguns e um valor padrão para outras chaves.

Finalmente, exportamos o esquema usando module.exports=mongoose.model ('Url', UrlSchema); . O primeiro parâmetro dentro de mongoose.model é a forma singular dos dados que devem ser armazenados, e o segundo parâmetro é o próprio esquema.

Construindo o URL e as rotas de índice

A rota do URL criará um URL curto a partir do URL original e o armazenará no banco de dados. Crie uma pasta chamada routes no diretório raiz e um arquivo chamado urls.js dentro dela. Vamos usar o roteador Express aqui. Primeiro, importe todos os pacotes necessários, assim.

 const Express=require ('express');
roteador const=Express.Router ();
const shortid=require ('shortid');
const Url=require ('../models/Url');
const utils=require ('../utils/utils');
require ('dotenv'). config ({path:'../config/.env'});

O arquivo utils.js dentro da pasta utils consiste em uma função que verifica se um URL passado é válido ou não. Este é o código para o arquivo utils.js .

 function validateUrl (value) { return/^ (?:(?:( ?: https? | ftp):)? \\/\\/) (?: \\ S + (?:: \\ S *)? @)? (?:( ?! (?: 10 | 127) (?: \\. \\ d {1,3}) {3}) (?! (?: 169 \\. 254 | 192 \\. 168) (?: \ \. \\ d {1,3}) {2}) (?! 172 \\. (?: 1 [6-9] | 2 \\ d | 3 [0-1]) (?: \\. \\ d {1,3}) {2}) (?: [1-9] \\ d? | 1 \\ d \\ d | 2 [01] \\ d | 22 [0-3]) ( ?: \\. (?: 1? \\ d {1,2} | 2 [0-4] \\ d | 25 [0-5])) {2} (?: \\. (?: [ 1-9] \\ d? | 1 \\ d \\ d | 2 [0-4] \\ d | 25 [0-4])) | (?: (?: [Az \\ u00a1-\\ uffff0-9]-*) * [az \\ u00a1-\\ uffff0-9] +) (?: \\. (?: [az \\ u00a1-\\ uffff0-9]-*) * [az \ \ u00a1-\\ uffff0-9] +) * (?: \\. (?: [az \\ u00a1-\\ uffff] {2,}))) (?:: \\ d {2,5} )? (?: [/? #] \\ S *)? $/I.test ( valor );
} module.exports={validateUrl};

Usaremos a solicitação de postagem HTTP no arquivo urls.js para gerar e postar os detalhes no banco de dados.

 const Express=require ('express');
roteador const=Express.Router ();
const shortid=require ('shortid');
const Url=require ('../models/Url');
const utils=require ('../utils/utils');
require ('dotenv'). config ({path:'../config/.env'}); //Short URL Generator
router.post ('/short', assíncrono (req, res)=> { const {origUrl}=req.body; const base=process.env.BASE; const urlId=shortid.generate (); if (utils.validateUrl (origUrl)) { tentar { deixe url=esperar Url.findOne ({origUrl}); if (url) { res.json (url); } senão { const shortUrl=`$ {base}/$ {urlId}`; url=novo Url ({ origUrl, shortUrl, urlId, data: nova data (), }); aguarde url.save (); res.json (url); } } catch (errar) { console.log (errar); res.status (500).json ('Erro do servidor'); } } senão { res.status (400).json ('URL original inválido'); }
}); módulo.exportações=roteador;

O const {origUrl}=req.body; extrairá o valor origUrl do corpo da solicitação HTTP. Em seguida, armazenamos o URL base em uma variável. const urlId=shortid.generate (); está gerando e armazenando um ID curto para uma variável.

Uma vez gerado, verificamos se o URL original é válido usando nossa função do diretório utils . Para URLs válidos, passamos para o bloco try .

Aqui, primeiro pesquisamos se o URL original já existe em nosso banco de dados com o método Url.findOne ({origUrl}); mongoose. Se encontrado, retornamos os dados no formato JSON; caso contrário, criamos um URL curto combinando o URL base e o ID curto.

Então, usando nosso modelo mongoose, passamos os campos para o construtor do modelo e salvamos no banco de dados com o método url.save (); . Depois de salvo, retornamos a resposta no formato JSON.

Erros inesperados para o bloco try são tratados no bloco catch e URLs inválidos que retornam false em nosso validateUrl function envia de volta uma mensagem de que o URL é inválido. Por fim, exportamos o roteador.

Anteriormente, precisávamos instalar o pacote body-parser , mas agora ele está integrado ao Express, então volte ao arquivo app.js e adicione estes dois linhas para usar body-parser :

//Analisador de corpo
app.use (Express.urlencoded ({extended: true}));
app.use (Express.json ());

Essas duas linhas nos ajudam a ler as solicitações recebidas. Após essas duas linhas de código, importe a rota de URL.

 app.use ('/api', require ('./routes/urls'));

Como estamos usando o endpoint /api , nosso endpoint completo se torna http://localhost: 3333/api/short . Aqui está um exemplo.

Dashboard De encurtador de URL com API como um terminal no URL de exemplo

Agora crie outro arquivo chamado index.js dentro da pasta routes para lidar com o processo de redirecionamento. Neste arquivo, importe as dependências necessárias.

Aqui, primeiro vamos pesquisar em nosso banco de dados o ID de URL curto que foi passado. Se o URL for encontrado, redirecionaremos para o URL original.

 const Express=require ('express');
roteador const=Express.Router ();
const Url=require ('../models/Url'); router.get ('/: urlId', assíncrono (req, res)=& gt; { tentar { const url=espera Url.findOne ({urlId: req.params.urlId}); if (url) { url.clicks ++; url.save (); return res.redirect (url.origUrl); } else res.status (404).json ('Não encontrado'); } catch (errar) { console.log (errar); res.status (500).json ('Erro do servidor'); }
}); módulo.exportações=roteador;

A solicitação HTTP GET está obtendo o ID do URL com a ajuda de : urlId . Então, dentro do bloco try , encontramos a URL usando o método Url.findOne , semelhante ao que fizemos na rota urls.js .

Se o URL for encontrado, aumentamos o número de cliques para o URL e salvamos o valor do clique. Por fim, redirecionamos o usuário para a URL original usando return res.redirect (url.origUrl); .

Se o URL não for encontrado, enviaremos uma mensagem JSON informando que o URL não foi encontrado. Qualquer exceção não capturada é tratada no bloco catch . Nós consoles registramos o erro e enviamos uma mensagem JSON de “Erro de servidor” Por fim, exportamos o roteador.

Importe a rota para o arquivo app.js , e nosso encurtador de URL está pronto para uso. Depois de importá-lo, nosso arquivo final app.js ficará assim:

 const Express=require ('Express');
const app=Express ();
const connectDB=require ('./config/db');
require ('dotenv'). config ({path:'./config/.env'}); connectDB (); //Body Parser
app.use (Express.urlencoded ({extended: true}));
app.use (Express.json ()); app.use ('/', require ('./routes/index'));
app.use ('/api', require ('./routes/urls')); //Configuração do servidor
const PORT=3333;
app.listen (PORTA, ()=> { console.log (`Servidor está rodando em PORT $ {PORT}`);
});

Conclusão

Neste artigo, aprendemos como construir uma API de serviço de encurtamento de URL do zero. Você pode integrá-lo a qualquer front-end que desejar e até mesmo criar um serviço encurtador de URL full-stack. Espero que tenha gostado de ler este artigo e aprendido algo novo ao longo do caminho. Você pode encontrar o código-fonte completo em meu repositório GitHub .

A postagem Construindo um encurtador de URL com Node.js apareceu primeiro no LogRocket Blog .