Dacă doriți să aflați despre ceva, ce modalitate mai bună decât construind un proiect în jurul lucrului pe care doriți să-l învățați?

În această postare de blog, vom învăța despre MongoDB, Mongoose, Node și alte tehnologii prin crearea unei aplicații simple de scurtare a adreselor URL.

Scurtătoarele de adrese URL sunt peste tot, de la linkuri pe care le partajați pe twitter până la servicii populare precum bit.ly. Dar v-ați întrebat vreodată cum ați putea crea un dispozitiv de scurtare rapidă a adreselor URL pentru dvs.?

Așa că vom trece prin practica practică de a construi un scurtator de adrese URL cu MongoDB ca soluție backend. Acest proiect vă va oferi încredere în cunoștințele dvs. și va consolida fiecare concept pe care îl învățați. Să începem.

Introducere în proiect

Vom folosi acest lucru gratuit Clasa de scurtare a adreselor URL de la codedamn pentru a începe practica practică și pentru a ne evalua progresul pe măsură ce continuăm.

Vom folosi următoarele tehnologii:

  • Mangosta ca ORM
  • MongoDB ca bază de date backend
  • Node.js ca backend
  • Un fișier JS încorporat simplu ca frontend

Vom finaliza acest proiect în 7 pași, care vă vor duce de la început până la finalizare. Să începem laboratoarele acum.

Partea 1: Configurarea serverului Express

Mai întâi să configurăm serverul nostru Node. Vom folosi Express ca cadru pentru această parte, deoarece este ușor de lucrat. Iată link către această parte.

Putem vedea că acesta este un exercițiu destul de ușor. Singurele două provocări pe care trebuie să le depășim sunt următoarele:

Aflati Node MongoDB prin crearea unui proiect de scurtare

Soluția ar putea arăta astfel:

// Initialize express server on PORT 1337
const express = require('express')
const app = express()

app.get('/', (req, res) => {
	res.send('Hello World! - from codedamn')
})

app.get('/short', (req, res) => {
	res.send('Hello from short')
})

app.listen(process.env.PUBLIC_PORT, () => {
	console.log('Server started')
})

Simplu și ușor. Creăm un alt traseu GET folosind app.getși ar trebui să facă treaba.

Partea 2: Configurarea motorului nostru de vizualizare

Acum, că suntem familiarizați cu instalarea Express, să aruncăm o privire la .ejs șablon pe care îl avem. Iată link către această parte.

Motorul EJS vă permite să transmiteți variabilele cu codul Node.js în HTML și să le iterați sau să le afișați înainte de a trimite un răspuns real către server.

Aruncați o privire rapidă la views/index.ejs fişier. Va arăta similar cu aspectul unui fișier HTML obișnuit, cu excepția faptului că puteți utiliza variabile.

Iată curentul nostru index.js fişier:

1611310808 75 Aflati Node MongoDB prin crearea unui proiect de scurtare

Acum, puteți vedea asta în index.js fișier avem linia app.set('view engine', 'ejs') . Îi spune Express să o folosească ejs ca motor implicit de modelare.

În cele din urmă, vedeți că folosim res.render și trecem doar numele fișierului, nu calea completă. Acest lucru se datorează faptului că Express va căuta automat în folderul de vizualizări pentru disponibilitate .ejs șabloane.

Trecem variabile ca al doilea argument, pe care îl putem accesa apoi în fișierul EJS. Vom folosi acest fișier mai târziu, dar deocamdată să trecem printr-o provocare rapidă.

Pentru a finaliza această provocare, trebuie doar să schimbăm numele din Mehul la orice altceva.

Pentru a trece peste această provocare, vizualizați index.ejs fișier mai întâi și apoi actualizați-vă numele la orice altceva doriți. Iată o soluție bună:

const express = require('express')
const app = express()

app.set('view engine', 'ejs')

app.get('/', (req, res) => {
	res.render('index', { myVariable: 'My name is John!' })
})

app.listen(process.env.PUBLIC_PORT, () => {
	console.log('Server started')
})

Partea 3: Configurarea MongoDB

Acum, că avem un pic de înțelegere frontend și backend, să mergem mai departe și să configurăm MongoDB. Iată link către această parte.

Vom folosi Mongoose pentru conectarea la MongoDB. Mongoose este un ORM pentru MongoDB.

Pur și simplu vorbind, MongoDB este un foarte slăbit baza de date și permite tot felul de operații pe orice.

Deși este bun pentru datele nestructurate, de cele mai multe ori suntem conștienți de ceea ce vor fi datele (cum ar fi înregistrările utilizatorilor sau înregistrările de plată). Astfel, putem defini un schemă pentru MongoDB folosind Mongoose. Acest lucru ne ușurează o mulțime de funcții.

De exemplu, odată ce avem o schemă, putem fi siguri că validarea datelor și orice verificări necesare vor fi gestionate automat de Mongoose. Mongoose ne oferă, de asemenea, o grămadă de funcții de ajutor pentru a ne ușura viața. Să-l configurăm acum.

Pentru a finaliza această parte, trebuie să ne ocupăm de următoarele puncte:

  • Pachetul Mongoose NPM a fost deja instalat pentru dvs. Poți direct require aceasta.
  • Conectați-vă la mongodb://localhost:27017/codedamn URL folosind mongoose.connect metodă.

Iată fișierul nostru actual index.js:

const express = require('express')
const app = express()
const mongoose = require('mongoose')

app.set('view engine', 'ejs')

app.get('/', (req, res) => {
	res.render('index')
})

app.post('/short', (req, res) => {
	const db = mongoose.connection.db
	// insert the record in 'test' collection

	res.json({ ok: 1 })
})

// Setup your mongodb connection here
// mongoose.connect(...)

// Wait for mongodb connection before server starts
app.listen(process.env.PUBLIC_PORT, () => {
	console.log('Server started')
})

Să completăm substituenții corespunzători cu codul relevant:

const express = require('express')
const app = express()
const mongoose = require('mongoose')

app.set('view engine', 'ejs')

app.get('/', (req, res) => {
	res.render('index')
})

app.post('/short', (req, res) => {
	const db = mongoose.connection.db
	// insert the record in 'test' collection
	db.collection('test').insertOne({ testCompleted: 1 })

	res.json({ ok: 1 })
})

// Setup your mongodb connection here
mongoose.connect('mongodb://localhost/codedamn', {
	useNewUrlParser: true,
	useUnifiedTopology: true
})
mongoose.connection.on('open', () => {
	// Wait for mongodb connection before server starts
	app.listen(process.env.PUBLIC_PORT, () => {
		console.log('Server started')
	})
})

Observați cum pornim serverul nostru HTTP numai când conexiunea noastră cu MongoDB este deschisă. Este în regulă, deoarece nu vrem ca utilizatorii să ajungă la rutele noastre înainte ca baza noastră de date să fie gata.

Folosim în cele din urmă db.collection aici pentru a insera o înregistrare simplă, dar vom avea în curând o modalitate mai bună de a interacționa cu baza de date folosind modele Mongoose.

Partea 4: Configurarea unei scheme Mongoose

Acum, că am avut experiența noastră practică cu implementarea MongoDB în ultima secțiune, haideți să scoatem schema pentru scurtatorul nostru de adrese URL. Iată link pentru această parte.

O schemă Mongoose ne permite să interacționăm cu colecțiile Mongo într-un mod abstract. Documentele bogate ale Mongoose expun, de asemenea, funcții de ajutor, cum ar fi .save care sunt suficiente pentru a efectua o interogare DB completă pentru a actualiza modificările din documentul dvs.

Iată cum va arăta schema noastră pentru scurtatorul de adrese URL:

const mongoose = require('mongoose')
const shortId = require('shortid')

const shortUrlSchema = new mongoose.Schema({
  full: {
    type: String,
    required: true
  },
  short: {
    type: String,
    required: true,
    default: shortId.generate
  },
  clicks: {
    type: Number,
    required: true,
    default: 0
  }
})

module.exports = mongoose.model('ShortUrl', shortUrlSchema)

Vom stoca acest fișier în models/url.js fişier. Odată ce avem schema, putem trece această parte a exercițiului. Trebuie să facem următoarele două lucruri:

  1. Creați acest model în models/url.js fişier. (Am făcut asta.)
  2. O cerere POST către /short ar trebui să adauge ceva la baza de date la acest model.

Pentru a face acest lucru, putem genera o nouă înregistrare folosind următorul cod:

app.post('/short', async (req, res) => {
	// insert the record using the model
	const record = new ShortURL({
		full: 'test'
	})
	await record.save()
	res.json({ ok: 1 })
})

Veți vedea că putem omite clicks și short pentru că au deja o valoare implicită în schemă. Aceasta înseamnă că Mongoose le va popula automat atunci când interogarea rulează.

Finalul nostru index.js fișierul pentru a trece această provocare ar trebui să arate astfel:

const express = require('express')
const app = express()
const mongoose = require('mongoose')
// import the model here
const ShortURL = require('./models/url')

app.set('view engine', 'ejs')

app.get('/', (req, res) => {
	res.render('index', { myVariable: 'My name is John!' })
})

app.post('/short', async (req, res) => {
	// insert the record using the model
	const record = new ShortURL({
		full: 'test'
	})
	await record.save()
	res.json({ ok: 1 })
})

// Setup your mongodb connection here
mongoose.connect('mongodb://localhost/codedamn')

mongoose.connection.on('open', () => {
	// Wait for mongodb connection before server starts
	app.listen(process.env.PUBLIC_PORT, () => {
		console.log('Server started')
	})
})

Partea 5: Legarea frontendului, backend-ului, + MongoDB

Acum că avem un mâner pe partea de backend, să revenim la frontend și să configurăm pagina noastră web. Acolo putem folosi Micsoreaza pentru a adăuga de fapt câteva înregistrări la baza de date. Iată linkul către această parte.

Dacă te uiți în interiorul views/index.ejs fișier, veți vedea că am trecut deja datele formularului pe backend /short traseu. Dar chiar acum nu o apucăm.

  • Puteți vedea că există o nouă linie numită app.use(express.urlencoded({ extended: false })) pe linia 8, care ne permite să citim răspunsul utilizatorului din formular.
  • În index.ejs fișier, puteți vedea că am setat name=”fullURL” care este modul în care putem primi adresa URL pe backend.

Iată-ne index.ejs fişier:

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<link
			rel="stylesheet"
			href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
		/>
		<title>codedamn URL Shortner Project</title>
	</head>
	<body>
		<div class="container">
			<h1>URL Shrinker</h1>
			<form action="/short" method="POST" class="my-4 form-inline">
				<label for="fullUrl" class="sr-only">URL</label>
				<input
					required
					placeholder="URL"
					type="url"
					name="fullUrl"
					id="fullUrl"
					class="form-control col mr-2"
				/>
				<button class="btn btn-success" type="submit">Shrink This!</button>
			</form>

			<table class="table table-striped table-responsive">
				<thead>
					<tr>
						<th>Full URL</th>
						<th>Short URL</th>
						<th>Clicks</th>
					</tr>
				</thead>
				<tbody>
					<% shortUrls.forEach(shortUrl => { %>
					<tr>
						<td><a href="<%= shortUrl.full %>"><%= shortUrl.full %></a></td>
						<td><a href="<%= shortUrl.short %>"><%= shortUrl.short %></a></td>
						<td><%= shortUrl.clicks %></td>
					</tr>
					<% }) %>
				</tbody>
			</table>
		</div>
	</body>
</html>

Aceasta este o provocare simplă, deoarece trebuie doar să introducem acest cod pentru a-l completa:

app.use(express.urlencoded({ extended: false }))

app.post('/short', async (req, res) => {
	// Grab the fullUrl parameter from the req.body
	const fullUrl = req.body.fullUrl
	console.log('URL requested: ', fullUrl)

	// insert and wait for the record to be inserted using the model
	const record = new ShortURL({
		full: fullUrl
	})

	await record.save()

	res.redirect('/')
})

În primul rând, preluăm adresa URL trimisă prin HTML folosind req.body.fullUrl. Pentru a activa acest lucru, avem și noi app.use(express.urlencoded({ extended: false })) ceea ce ne permite să obținem datele formularului.

Apoi ne creăm și salvăm înregistrarea la fel cum am făcut-o ultima dată. În cele din urmă, redirecționăm utilizatorul înapoi la pagina de pornire, astfel încât utilizatorul să poată vedea noile legături.

Bacsis: Puteți face această aplicație mai interesantă efectuând o cerere Ajax către API-ul backend în loc de trimiterea formularului tipic. Dar îl vom lăsa aici, deoarece se concentrează mai mult pe configurarea MongoDB + Node în loc de JavaScript.

Partea 6: Afișarea adreselor URL scurte pe frontend

Acum că stocăm adresele URL scurtate în MongoDB, haideți să le prezentăm și pe frontend.

Amintiți-vă variabilele noastre transmise la ejs șablon dinainte? Acum le vom folosi.

Bucla șablon pentru ejs a fost făcut pentru tine în index.ejs fișier (puteți vedea bucla de mai sus). Cu toate acestea, trebuie să scriem interogarea Mongoose pentru a extrage datele din această secțiune.

Dacă vedem șablonul, îl vom vedea în index.js avem următorul cod:

app.get('/', (req, res) => {
	const allData = [] // write a mongoose query to get all URLs from here
	res.render('index', { shortUrls: allData })
})

Avem deja un model definit la noi pentru a interoga date de la Mongoose. Să-l folosim pentru a obține tot ce avem nevoie.

Iată fișierul soluției noastre:

const express = require('express')
const app = express()
const mongoose = require('mongoose')
// import the model here
const ShortURL = require('./models/url')

app.set('view engine', 'ejs')
app.use(express.urlencoded({ extended: false }))

app.get('/', async (req, res) => {
	const allData = await ShortURL.find()
	res.render('index', { shortUrls: allData })
})

app.post('/short', async (req, res) => {
	// Grab the fullUrl parameter from the req.body
	const fullUrl = req.body.fullUrl
	console.log('URL requested: ', fullUrl)

	// insert and wait for the record to be inserted using the model
	const record = new ShortURL({
		full: fullUrl
	})

	await record.save()

	res.redirect('/')
})

// Setup your mongodb connection here
mongoose.connect('mongodb://localhost/codedamn', {
	useNewUrlParser: true,
	useUnifiedTopology: true
})

mongoose.connection.on('open', async () => {
	// Wait for mongodb connection before server starts

	// Just 2 URLs for testing purpose
	await ShortURL.create({ full: 'http://google.com' })
	await ShortURL.create({ full: 'http://codedamn.com' })

	app.listen(process.env.PUBLIC_PORT, () => {
		console.log('Server started')
	})
})

Puteți vedea că a fost la fel de ușor ca a face await ShortURL.find() în allData variabil. Următoarea parte este în care lucrurile devin un pic dificile.

Partea 7: Efectuarea redirecționării

Aproape am terminat! Acum avem adresa URL completă și adresa URL scurtă stocate în baza de date și le afișăm și pe frontend.

Dar veți observa că redirecționarea nu funcționează chiar acum și vom primi o eroare Express.

Să remediem asta. Puteți vedea în index.js fișier există o nouă rută dinamică adăugată la sfârșit care gestionează aceste redirecționări:

app.get('/:shortid', async (req, res) => {
	// grab the :shortid param
	const shortid = ''

	// perform the mongoose call to find the long URL

	// if null, set status to 404 (res.sendStatus(404))

	// if not null, increment the click count in database

	// redirect the user to original link
})

Provocările noastre pentru această parte arată astfel:

1611310808 554 Aflati Node MongoDB prin crearea unui proiect de scurtare

Bine. În primul rând, trebuie să extragem adresa URL completă atunci când vizităm o adresă URL scurtă. Iată cum vom face asta:

app.get('/:shortid', async (req, res) => {
	// grab the :shortid param
	const shortid = req.params.shortid

	// perform the mongoose call to find the long URL
	const rec = await ShortURL.findOne({ short: shortid })

	// ...
})

Acum, dacă vedem că rezultatul nostru este nul, vom trimite un statut 404:

app.get('/:shortid', async (req, res) => {
	// grab the :shortid param
	const shortid = req.params.shortid

	// perform the mongoose call to find the long URL
	const rec = await ShortURL.findOne({ short: shortid })

	// if null, set status to 404 (res.sendStatus(404))
	if (!rec) return res.sendStatus(404)

	res.sendStatus(200)	
})

Aceasta trece de prima noastră provocare. Apoi, dacă avem de fapt un link, să redirecționăm utilizatorul și să creștem și numărul de clicuri în baza de date.

app.get('/:shortid', async (req, res) => {
	// grab the :shortid param
	const shortid = req.params.shortid

	// perform the mongoose call to find the long URL
	const rec = await ShortURL.findOne({ short: shortid })

	// if null, set status to 404 (res.sendStatus(404))
	if (!rec) return res.sendStatus(404)

	// if not null, increment the click count in database
	rec.clicks++
	await rec.save()

	// redirect the user to original link
	res.redirect(rec.full)
})

În acest fel, putem incrementa și stoca din nou rezultatul în baza de date. Și asta ar trebui să treacă peste toate provocările noastre.

Concluzie

Felicitări! Tocmai ați creat singur un dispozitiv de scurtare a adresei URL de lucru complet folosind Express + Node + MongoDB. Dă-ți o palmă pe spate!

Codul sursă final este disponibil pe GitHub.

Dacă aveți feedback despre acest articol sau despre sălile de clasă codificate, nu ezitați să mă contactați Stare de nervozitate. Sa discutam 🙂