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.
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
paraprocess.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 comofalse
por padrão. Aqui, ele é definido comotrue
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.
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 .