sql >> Base de Datos >  >> NoSQL >> MongoDB

Cómo construir un acortador de URL con Node.js y MongoDB

En esta publicación, le mostraremos cómo crear un servicio de acortamiento de URL como bit.ly o goo.gl usando Express.js (Node.js) y MongoDB. Aquí hay una demostración del producto final que construiremos a través de nuestra plataforma de alojamiento MongoDB.

¿Cómo funciona un acortador de URL?

En un nivel muy alto, el acortador de URL funciona tomando una URL ingresada y creando una versión relativamente abreviada simplificada en un formato fácil de compartir. El hash acortado se generará mediante la codificación base de un contador de incremento automático y crea un hash mínimo de tres caracteres que aumenta a medida que aumenta la cantidad de URL almacenadas.

Cuando se visita la versión abreviada de la URL, el servicio decodificará el hash para obtener la URL original almacenada en MongoDB y luego redirigirá a su usuario a ella.

Cómo empezar

Aquí hay una lista de las tecnologías que usaremos para crear el acortador de URL en este tutorial:

  • Express.js (back-end de Node.js)

    Un marco de aplicaciones web para Node.js. Lo usaremos para crear una API para acortar las URL y redirigir a los usuarios a la URL original.

  • MongoDB (almacenamiento de URL)

    Una base de datos NoSQL perfecta para esta aplicación. Proporciona un diseño de esquema flexible y es fácil comenzar con él. En este tutorial, usaremos un clúster MongoDB compartido en ScaleGrid. Se tarda menos de 5 minutos en configurarlo y puedes crear una prueba gratuita de 30 días aquí para empezar.

  • HTML, CSS, JavaScript (front-end)

    HTML, CSS y JavaScript se utilizarán para crear el front-end de la aplicación que sus usuarios utilizarán para acortar las URL.

Cómo construir un acortador de URL con Node.js y MongoDBClick To Tweet

Tutorial de acortador de URL

  1. Configurar la estructura de la base de datos MongoDB

    Empecemos por crear un clúster de MongoDB compartido en ScaleGrid. Esta es la forma más fácil de crear un clúster rápido, pero también puede instalar MongoDB en su máquina y comenzar allí.

    Una vez que se crea el clúster, se le proporcionará una cadena de conexión que se puede copiar con un solo clic desde la página Detalles del clúster. Necesitaremos esta cadena para conectarnos al clúster desde nuestra aplicación. Recuerde, nunca comparta su cadena de conexión con nadie.

    Necesitaremos dos colecciones para el acortador de URL:

    • Colección 1

      Una colección para almacenar la URL y el ID generado dinámicamente:

    • Colección 2

      Una colección para mantener el contador que se incrementará automáticamente cuando se almacene una nueva URL en la colección anterior. Se crea un nuevo documento en la colección anterior con este contador recién incrementado:

    Es importante tener en cuenta que no estamos almacenando los hash en ninguna parte de la base de datos. El hash se codificará en base y se descodificará dinámicamente con el algoritmo general que dará como resultado la identificación única almacenada en la primera colección. Este ID nos traerá la URL original a la que el usuario será redirigido.

    Para este tutorial, utilizaremos el mecanismo común de codificación y decodificación base64 para generar nuestro exclusivo hash acortado. Para obtener más información sobre la codificación/descodificación de cadenas usando base64, consulte nuestro siguiente documento web de MDN.

  2. Configurar el servidor Express.js

    Esta es una lista de las dependencias necesarias para configurar nuestro backend de Node.js:

    • express (aplicación base)
    • body-parser (complemento para analizar datos enviados a través de solicitudes HTTP)
    • btoa (codificación base64)
    • atob (descodificación base64)
    • dotenv (almacenamiento de la cadena de conexión en un archivo .env para fines de desarrollo)
    • mangoose (adaptador para MongoDB en Node.js)

    Esta es una versión de muestra del paquete.json que puede usar para configurar la aplicación:

    {
      "name": "sg-url-shortener",
      "version": "1.0.0",
      "description": "A simple URL shortener built with Node.js and MongoDB",
      "dependencies": {
        "atob": "^2.0.3",
        "body-parser": "^1.15.2",
        "btoa": "^1.1.2",
        "dotenv": "^4.0.0",
        "express": "^4.10.2",
        "mongoose": "^4.13.7"
      },
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "engines": {
        "node": "4.8.4"
      }
    }
    

    Ejecute “npm install” para instalar todas las dependencias requeridas.

    Una vez que se hayan configurado todas nuestras dependencias, debemos conectarnos a nuestro clúster MongoDB compartido. Cree un archivo .env en la raíz del proyecto y agréguele la cadena de conexión. Puede obtener la cadena de conexión de la página Detalles del clúster en la pestaña Descripción general en la consola de ScaleGrid.

    connectionString=mongodb://user:password@devservers

    Antes de comenzar a escribir código, es una buena práctica visualizar el flujo de la aplicación para que comprendamos bien cómo funcionará el proceso de acortamiento. Aquí hay un diagrama que muestra el proceso de acortamiento de URL:

    Aquí hay un diagrama que muestra el proceso de redirección cuando se visita una URL abreviada:

    Ahora que hemos visualizado todo el proceso, es hora de traducir los diagramas de flujo anteriores en código.

  3. Inicializar la aplicación

    Antes de comenzar a escribir la lógica comercial, debemos inicializar nuestra aplicación con nuestros módulos de nodo y configurar un servidor.

    Cargar archivos .env solo en modo desarrollador. Dado que la aplicación de demostración está alojada en Heroku, se ha creado una variable de entorno desde el panel de control de Heroku que ya contiene la cadena de conexión allí:

    if(process.env.NODE_ENV !== 'production') {
        require('dotenv').load();
    }

    Inicialización de la aplicación, configuración del servidor y del middleware. Tenga en cuenta que también estamos obteniendo la cadena de conexión de la variable de entorno:

    var express = require('express'),
        bodyParser = require('body-parser'),
        app = express(),
        http = require('http').Server(app),
        mongoose = require('mongoose'),
        btoa = require('btoa'),
        atob = require('atob'),
        promise,
        connectionString = process.env.connectionString,
        port = process.env.PORT || 8080;
    
    http.listen(port, function() {
        console.log('Server Started. Listening on *:' + port);
    });
    
    app.use(express.static('public'));
    app.use(bodyParser.urlencoded({
        extended: true
    }));

    Ruta base para cargar el front-end de nuestra aplicación:

    app.get('/', function(req, res) {
        res.sendFile('views/index.html', {
            root: __dirname
        });
    });
    
  4. Almacenamiento de URL en MongoDB

    Empecemos creando los esquemas de colección para almacenar datos. Como se discutió anteriormente, necesitamos dos colecciones:una para almacenar el contador de incremento automático y la otra para almacenar las URL.

    var countersSchema = new mongoose.Schema({
        _id: { type: String, required: true },
        count: { type: Number, default: 0 }
    });
    
    var Counter = mongoose.model('Counter', countersSchema);
    
    var urlSchema = new mongoose.Schema({
        _id: {type: Number},
        url: '',
        created_at: ''
    });
    
    urlSchema.pre('save', function(next) {
        console.log('running pre-save');
        var doc = this;
        Counter.findByIdAndUpdate({ _id: 'url_count' }, { $inc: { count: 1 } }, function(err, counter) {
            if(err) return next(err);
            console.log(counter);
            console.log(counter.count);
            doc._id = counter.count;
            doc.created_at = new Date();
            console.log(doc);
            next();
        });
    });
    
    var URL = mongoose.model('URL', urlSchema);
    

    El código anterior crea las dos colecciones y configura nuestra base de datos para almacenar estas colecciones. También usamos un gancho de preguardado para el esquema de URL, ya que necesitamos incrementar automáticamente el contador y registrar la fecha y la hora en que se creó la URL.

    A continuación, debemos asegurarnos de iniciar nuestra aplicación desde cero y de eliminar todas las entradas anteriores. Una vez que reiniciamos, inicializaremos nuestro contador con un valor inicial de 10,000 para configurar el proceso de acortamiento de URL. Puede comenzar con cualquier valor. Esto fue elegido al azar y se incrementará automáticamente en un valor de uno.

    promise = mongoose.connect(connectionString, {
        useMongoClient: true
    });
    
    promise.then(function(db) {
        console.log('connected!');
        URL.remove({}, function() {
            console.log('URL collection removed');
        })
        Counter.remove({}, function() {
            console.log('Counter collection removed');
            var counter = new Counter({_id: 'url_count', count: 10000});
            counter.save(function(err) {
                if(err) return console.error(err);
                console.log('counter inserted');
            });
        });
    });
    

    ¡Nuestra aplicación ahora está lista para comenzar a aceptar y acortar URLs! Creemos una API POST que nuestro front-end usará para enviar la URL:

    app.post('/shorten', function(req, res, next) {
        console.log(req.body.url);
        var urlData = req.body.url;
        URL.findOne({url: urlData}, function(err, doc) {
            if(doc) {
                console.log('entry found in db');
                res.send({
                    url: urlData,
                    hash: btoa(doc._id),
                    status: 200,
                    statusTxt: 'OK'
                });
            } else {
                console.log('entry NOT found in db, saving new');
                var url = new URL({
                    url: urlData
                });
                url.save(function(err) {
                    if(err) return console.error(err);
                    res.send({
                        url: urlData,
                        hash: btoa(url._id),
                        status: 200,
                        statusTxt: 'OK'
                    });
                });
            }
        });
    });

    Como se describe en el diagrama de flujo, una vez que se recibe una URL válida, verificamos su existencia en la base de datos.

    Si se encuentra, descodificamos el campo _id correspondiente y devolvemos el hash. Nuestro front-end construye la URL acortada y se la presenta al usuario para que la redirija.

    Si no se encuentra ninguna URL, guardamos un nuevo documento en la colección. Recuerde, se ejecuta un paso previo al guardado cada vez que se guarda la URL. Esto incrementará automáticamente el contador y registrará la fecha y hora actuales. Después de agregar el documento, enviamos el hash a nuestro front-end, que construye la URL acortada y se la presenta al usuario para que la redirija.

  5. Usuarios de redirección

    ¡Casi hemos terminado! Una vez que se han creado nuestras URL acortadas, necesitamos una forma de redirigir al usuario cuando se visita una URL acortada.

    app.get('/:hash', function(req, res) {
        var baseid = req.params.hash;
        var id = atob(baseid);
        URL.findOne({ _id: id }, function(err, doc) {
            if(doc) {
                res.redirect(doc.url);
            } else {
                res.redirect('/');
            }
        });
    });

    El código anterior busca un hash en la URL acortada, base64 lo decodifica, verifica si esa ID está presente en la colección y redirige al usuario en consecuencia. Si no se encuentra ninguna ID, se redirige al usuario a la página de inicio del acortador de URL.

    Para ver el código de front-end, consulte el repositorio de GitHub mencionado al final de esta publicación. Es esencialmente un campo de cuadro de texto con un botón para enviar la URL al back-end y está fuera del alcance de este artículo.

Más mejoras en el acortador de URL

¡Y listo! Tenemos un acortador de URL básico que se puede usar internamente para simplificar sus enlaces. Si desea agregar más campanas y silbatos, aquí hay una lista de cosas que puede implementar adicionalmente:

  • Mejor división de código
  • Algoritmo de acortamiento mejor/personalizado para un hash de caracteres más pequeño (por ejemplo, base52)
  • Compartir URL acortadas en las redes sociales
  • Copia de URL con un clic
  • Hashes personalizados
  • Registro de usuario y URL acortadas asociadas

El código completo está disponible aquí: Ejemplos de código de acortador de URL de ScaleGrid:Github Una aplicación de demostración está alojada en Heroku:Demostración de acortador de URL de ScaleGrid

Como siempre, si construyes algo increíble, envíanos un tweet al respecto @scalegridio. Si necesita ayuda con el alojamiento para MongoDB® o el alojamiento para Redis™*, comuníquese con nosotros en [email protected].