Bouw webapplicaties met Node.js

Invoering

Afgezien van het bouwen van API's, is Node.js geweldig voor het bouwen van standaard webapplicaties. Het heeft krachtige tools om te voldoen aan de smaak van webontwikkelaars. In deze zelfstudie bouwt u een webtoepassing die kan dienen als een lokale bibliotheek. 

Tijdens het bouwen zul je meer te weten komen over sommige soorten middleware, je zult zien hoe je formulierinzending verwerkt in Node.js, en je zult ook in staat zijn om te verwijzen naar twee modellen.

Laten we beginnen.

Ermee beginnen

Begin met het installeren van de express-generator op uw machine.

npm install express-generator -g

Voer de express generatoropdracht uit om uw toepassing te genereren.

express tutsplus-library --view = pug
 create: tutsplus-library create: tutsplus-library / package.json create: tutsplus-library / app.js create: tutsplus-library / public create: tutsplus-library / routes create: tutsplus-library / routes / index.js create: tutsplus-library / routes / users.js create: tutsplus-library / views create: tutsplus-library / views / index.pug create: tutsplus-library / views / layout.pug create: tutsplus-library / views / error.pug create : tutsplus-library / bin create: tutsplus-library / bin / www create: tutsplus-library / public / javascripts create: tutsplus-library / public / images create: tutsplus-library / public / stylesheets create: tutsplus-library / public / stylesheets / style.css install dependencies: $ cd tutsplus-library && npm install voer de app uit: $ DEBUG = tutsplus-library: * npm start

Migreer nu naar uw werkende, open package.json en maak de afhankelijkheden vergelijkbaar met wat ik hieronder heb.

# package.json "name": "tutsplus-library", "version": "0.0.0", "private": true, "scripts": "start": "node ./bin/www", "afhankelijkheden": "body-parser": "~ 1.17.1", "connect-flash": "^ 0.1.1", "cookie-parser": "~ 1.4.3", "debug": "~ 2.6.3 "," express ":" ~ 4.15.2 "," uitdrukkelijke berichten ":" ^ 1.0.1 "," uitdrukkelijke sessie ":" ^ 1.15.5 "," uitdrukkelijke validator ":" ^ 4.2.1 "," mongoose ":" ^ 4.11.12 "," morgan ":" ~ 1.8.1 "," pug ":" ~ 2.0.0-beta11 "," serve-favicon ":" ~ 2.4. 2 "

Voer de opdracht uit om de pakketten te installeren.

npm installeren

Stel het Entry-bestand in

app.js is gemaakt toen u de generatoropdracht uitvoerde; u moet echter extra configuratie instellen. Bewerk het bestand zodat het lijkt op wat ik hieronder heb.

# app.js var express = require ('express'); var path = require ('path'); var favicon = require ('serve-favicon'); var logger = require ('morgan'); var cookieParser = require ('cookie-parser'); var bodyParser = require ('body-parser'); const session = require ('express-session') const expressValidator = require ('express-validator') const flash = require ('connect-flash') const mongoose = require ('mongoose') // 1 const genres = vereisen ( ' ./routes/genres); const books = vereisen ('./ routes / boeken'); var app = express (); // 2 mongoose.Promise = global.Promise const mongoDB = process.env.MONGODB_URI || 'mongodb: //127.0.0.1/tutsplus-library' mongoose.connect (mongoDB) // bekijk engine setup app.set ('views', path.join (__ dirname, 'views')); app.set ('view engine', 'pug'); // uncomment na het plaatsen van uw favicon in / public //app.use(favicon(path.join (__domeinnaam, 'public', 'favicon.ico'))); app.use (logger (dev)); app.use (bodyParser.json ()); app.use (bodyParser.urlencoded (extended: false)); app.use (cookieParser ()); app.use (express.static (path.join (__ dirname, 'public'))); // 3 app.use (sessie (secret: 'secret', saveUninitialized: true, resave: true)) // 4 app.use (expressValidator (errorFormatter: function (param, msg, value) var namespace = param.split ('.'), root = namespace.shift (), formParam = root while (namespace.length) formParam + = '[' + namespace.shift () + ']' return param: formParam, msg: msg, waarde: waarde)) // 5 app.use (flash ()) app.use (functie (req, res, next) res.locals.messages = require ('uitdrukkelijke berichten') next ()) // 6 app.use ('/ genres', genres); app.use ('/ books', books); // catch 404 en doorsturen naar error handler app.use (functie (req, res, next) var err = new Error ('Not Found'); err.status = 404; next (err);); // error handler app.use (functie (err, req, res, next) // set locals, geeft alleen fout in ontwikkeling res.locals.message = err.message; res.locals.error = req.app.get ('env') === 'ontwikkeling'? err: ; // render de foutpagina res.status (err.status || 500); res.render ('error');); module.exports = app;
  1. U hebt de twee routes nodig die u gebruikt bij het bouwen van deze applicatie. U maakt het routesbestand binnenkort aan. De vereiste routes worden als waarden toegewezen aan twee verschillende variabelen die worden gebruikt bij het instellen van de middleware voor uw routes.
  2. Je hebt Mongoose ingesteld om te gebruiken global.Promise. De variabele MongoDB is toegewezen aan MONGODB_URI van uw omgeving of het pad naar uw lokale mongo-server. Deze variabele wordt doorgegeven als een argument om verbinding te maken met de actieve MongoDB-server.
  3. U stelt sessie-middleware in met behulp van express-sessie. Deze middleware is belangrijk omdat u in sommige delen van uw toepassing flash-berichten zult weergeven.
  4. U stelt middleware in voor validatie. Deze middleware wordt gebruikt om formulierinvoer te valideren en ervoor te zorgen dat gebruikers van de applicatie geen leeg formulier indienen. Bij de validatie wordt een pakket geïnstalleerd, express-validator.
  5. Je stelt middleware in die handig is bij het weergeven van flashberichten. Deze middleware maakt gebruik van connect-flash.
  6. De routes voor de toepassing zijn ingesteld om gebruik te maken van het routesbestand dat u nodig hebt. Verzoeken die verwijzen naar / genres en /boeken maakt respectievelijk gebruik van de genres- en boekenroutes-bestanden. Op dit moment heb je nog niet de routesbestanden aangemaakt, maar dat ga je binnenkort doen.

Boek en Genre Model

Het boekmodel maakt gebruik van Mongoose Schema om te definiëren hoe de boeken worden gestructureerd. Maak een map met de naam modellen, en een nieuw bestand genaamd Book.js. Hier is hoe het eruit ziet.

# models / Book.js const mongoose = require ('mongoose') mongoose.Promise = global.Promise const Schema = mongoose.Schema const bookSchema = Schema (name: type: String, trim: true, required: 'Please enter een boeknaam ', description: type: String, trim: true, auteur: type: String, trim: true,, genre: [type: Schema.Types.ObjectId, ref:' Genre '] ) module.exports = mongoose.model ('Book', bookSchema)

Hier heb je vier velden. Het laatste veld wordt gebruikt om het genre op te slaan waarvan elk boek deel uitmaakt. Het genre-veld verwijst hier naar het Genre-model, dat vervolgens wordt gemaakt. Daarom is het type ingesteld op Schema.Types.ObjectId, dat is waar de id's van elk genre waarnaar wordt verwezen worden opgeslagen. ref specificeert het model waarnaar u verwijst. Merk op dat het genre wordt opgeslagen als een array, wat betekent dat een boek meer dan één genre kan hebben.

Laten we doorgaan met het maken van het Genre-model.

# models / genre.js const mongoose = vereisen ('mongoose') mongoose.Promise = global.Promise const Schema = mongoose.Schema const genreSchema = Schema (name: type: String, trim: true, required: 'Please enter a Genre name ') module.exports = mongoose.model (' Genre ', genreSchema)

Voor je genre heb je slechts één veld nodig: naam.

Genre Index-route en weergave

Voor deze zelfstudie maakt u gebruik van twee routespaden voor uw genre: een pad om nieuwe genres toe te voegen, en een ander pad met de genres die u hebt. Maak een bestand in uw opgeroepen map directory genres.js.

Begin met het vereisen van alle modules die u gaat gebruiken.

# routes / genres.js var express = require ('express'); var router = express.Router (); const mongoose = require ('mongoose') const Genre = require ('... / models / Genre')

Voeg vervolgens de route toe die het indexbestand voor uw genres verwerkt.

router.get ('/', (req, res, volgende) => const genres = Genre.find (). exec () .then ((genres) => res.render ('genres',  genres: genres), (err) => go err));

Deze route wordt gebeld wanneer verzoeken worden gedaan / genres. Hier noem je de find-methode op je Genre-model om alle genres te verkrijgen die zijn gemaakt. Deze genres worden vervolgens gerenderd op een sjabloon met de naam genres. Laten we doorgaan en dat creëren, maar eerst moet je je update updaten layout.pug om er zo uit te zien:

# views / layout.pug doctype html html head title = title link (rel = 'stylesheet', href = "/ stylesheets / style.css") link (rel = 'stylesheet', href = "https://bootswatch.com /paper/bootstrap.css ") script (src = 'https: //ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js') script (src = 'https: // maxcdn .bootstrapcdn.com / bootstrap / 3.3.7 / js / bootstrap.min.js ') body .container-fluid block header nav.navbar.navbar-inverse .container-fluid .navbar-header button.navbar-toggle.collapsed ( type = 'knop', data-toggle = "samenvouwen", data-doel = "# bs-example-navbar-collapse-2") span.sr-only Schakelen tussen navigatie span.icon-bar span.icon-bar span. icon-bar a.navbar-brand (href = '#') Lokale bibliotheek # bs-example-navbar-collapse-2.collapse.navbar-collapse ul.nav.navbar-nav.navbar-right li a (href = ' / books ') Boeken bekijken li a (href =' / books / add ') Nieuw boek toevoegen li a (href =' / genres ') Genres bekijken li a (href =' / genres / add ') Nieuwe inhoud van genreblok toevoegen

Dit geeft je uitzicht een mooie structuur om de navigatie te vergemakkelijken. Maak nu een weergavebestand met de naam genre.pug. In dit bestand loop je door de gemaakte genres en voer je elk genre uit in een ongeordende lijst.

Hier is hoe het bestand eruit zou moeten zien.

# views / genres.pug breidt layoutblokinhoud uit h1 Genre ul.well.well-lg elk genre, i in genres li.well.well-sm p # genre.name

Voeg nieuwe genre-routes en weergave toe

Ga terug naar jouw routes / genres.js om de routes toe te voegen die de creatie van nieuwe genres zullen behandelen.

# routes / genres.js // 1 router.get ('/ add', (req, res, next) => res.render ('addGenre')) // 2 router.post ('/ add', (req, res, next) => req.checkBody ('naam', 'Naam is verplicht'). notEmpty () const errors = req.validationErrors () if (errors) console.log (errors) res.render ('addgenres', genre, errors) const genre = (nieuw genre (req.body)). save () .then ((data) => res.redirect ('/ genres')) .catch ((fouten) => console.log ('oeps ...') console.log (fouten))) // 3 module.exports = router;
  1. De taak van deze router is om eenvoudig de pagina weer te geven voor het toevoegen van nieuwe routes. Deze router wordt gebeld wanneer verzoeken worden gedaan / Genres / add pad.
  2. Deze router verwerkt de verzending van het formulier. Wanneer het formulier wordt ingediend, controleren we of de gebruiker een naam heeft ingevoerd. Als er geen naam is ingevoerd, wordt de pagina opnieuw gerenderd. Als de controles goed zijn om te gaan, wordt het genre opgeslagen en wordt de gebruiker omgeleid naar de / genres pagina.
  3. De module wordt geëxporteerd als een router.

Nu kunt u doorgaan en de pagina maken voor het toevoegen van een nieuw genre.

# views / addGenre.pug breidt layoutblokinhoud uit .row .col-md-12 h1 Voeg Boekformulier toe (methode = "POST", action = "/ genres / add") .form-group label.col-lg-2. control.label Naam .col-lg-10 input.form-control (type = "text", name = "name") .form-group .col-lg-10.col-lg-offset-2 input.button. btn.btn-primary (type = 'submit', value = "Submit") als fouten voor fouten in fouten li! = error.msg

Boeken Routes en weergave

Maak een nieuw routebestand voor boeken en geef het een naam books.js. Zoals je eerder met het genre deed, begin je met het vereisen van de nodige modules.

# routes / books.js var express = require ('express'); var router = express.Router (); const mongoose = require ('mongoose') const Book = require ('... / models / Book') const Genre = require ('... / models / Genre')

Stel vervolgens de router in voor het weergeven van alle boeken die in de bibliotheek zijn opgeslagen. Probeer dat alleen uit op de manier zoals jij dat van het genre hebt ingesteld; u kunt altijd teruggaan om correcties aan te brengen.

Ik neem aan dat je dat geprobeerd hebt - hier is hoe het eruit moet zien.

router.get ('/', (req, res, next) => const books = Book.find (). exec (). then ((books) => res.render ('books',  books: books), (err) => go err));

Wanneer deze router wordt gebeld, wordt er een verzoek ingediend om alle boeken te vinden die in de database zijn opgeslagen. Als alles goed gaat, worden de boeken getoond op de /boeken pagina, anders wordt er een fout gegenereerd.

U moet een nieuw bestand maken voor het weergeven van alle boeken, en hier moet het eruit zien.

# views / books.pug breidt lay-outblokinhoud uit h1 Boeken ul.well.well-lg elk boek, i in boeken li.well.well-sm a (href = '/ books / show / $ book.id') # book.name p = book.description

U loopt gewoon door de geretourneerde boeken en voert de naam en beschrijving van elk boek uit met een ongeordende lijst. De naam van het boek verwijst naar de individuele pagina van het boek.

Nieuwe boekroutes en weergave toevoegen

De volgende router die u instelt, zal de toevoeging van nieuwe boeken afhandelen. Hier worden twee routers gebruikt: de ene pagina wordt gewoon weergegeven en de andere behandelt de verzending van het formulier.

Dit is hoe de routers eruit zien.

router.get ('/ add', (req, res, next) => const genres = Genre.find (). exec () .then ((genres) => res.render ('addBooks', genres)) .catch ((err) => gooi err)) router.post ('/ add', (req, res, next) => req.checkBody ('name', 'Name is vereist '). notEmpty () req.checkBody (' description ',' Description is required '). notEmpty () req.checkBody (' genre ',' Genre is vereist '). notEmpty const errors = req.validationErrors () if (errors) console.log (errors) res.render ('addBooks', book, errors) const book = (nieuw boek (req.body)). save () .then ((data) => res.redirect ('/ books')) .catch ((errors) => console.log ('oops ...')))

In de eerste router geeft u de / addBooks pagina. Deze router wordt aangeroepen wanneer een aanvraag wordt gedaan /toevoegen pad. Omdat toegevoegde boeken genres zouden moeten hebben, wilt u de genres weergeven die in de database zijn opgeslagen.

 const genres = Genre.find (). exec () .then ((genres) => 

De bovenstaande code vindt alle genres in uw database en retourneert deze in de variabel genres. Hiermee kun je de genres doorlopen en ze weergeven als selectievakjes.

De tweede router verwerkt het indienen van het formulier. Eerst controleert u de hoofdtekst van het verzoek om ervoor te zorgen dat sommige velden niet leeg zijn. Dit is waar de express-validator middleware die u instelt app.js komt handig. Als er fouten zijn, wordt de pagina opnieuw gerenderd. Als er geen zijn, wordt de nieuwe instantie Book opgeslagen en wordt de gebruiker doorgestuurd naar de pagina / books.

Laten we doorgaan en hier de standpunten voor creëren.

Maak een nieuw beeldbestand met de naam addBooks.pug. Merk op dat de naam van de weergave overeenkomt met de eerste parameter gegeven aan res.render. Dit komt omdat u een sjabloon rendert. Tijdens omleiding geeft u eenvoudigweg het pad door waarnaar u wilt doorsturen, zoals u deed met res.redirect ( '/ boeken').

Als je dat hebt vastgesteld, is hier hoe de visies eruit zouden moeten zien.

# views / addBooks.pug breidt layoutblokinhoud uit .row .col-md-12 h1 Voeg Boekformulier toe (methode = "POST", action = "/ books / add") .form-group label.col-lg-2. controlelabel Naam .col-lg-10 input.form-control (type = "text", name = "name") .form-group label.col-lg-2.control-label Auteur .col-lg-10 input.form-control (type = "text", name = "author") .form-group label.col-lg-2.control-label Boekbeschrijving .col-lg-10 textarea # textArea.form-control (rijen = '3', naam = "beschrijving") .form-group label.col-lg-2.control-label Genre .col-lg-10 voor genre in genres .checkbox input.checkbox (type = 'checkbox', naam = "genre", id = genre._id, waarde = genre._id, checked = genre.checked) label (for = genre._id) # genre.name .form-group .col-lg-10.col- lg-offset-2 input.button.btn.btn-primary (type = 'submit', value = "Submit") als fouten voor fouten in fouten li! = error.msg 

Het belangrijkste om op te merken is de vormactie en -methode. Wanneer op de knop Verzenden wordt geklikt, maakt u een POST verzoek om / Boeken / toevoegen. Nog een ding - nogmaals loop je door de verzameling genres die terugkomt en geef ze elk weer.

Boek Toon route en uitzicht

Laten we de route neerzetten om de aanvragen voor elke boekenpagina af te handelen. Terwijl je daar bent, is het belangrijk om ook je module te exporteren.

# routes / books.js router.get ('/ show /: id', (req, res, volgende) => const book = Book.findById (_id: req.params.id) .populate (path : 'genre', model: 'Genre', vul aan: path: 'genre', model: 'Book') .exec () .then ((book) => res.render ('book',  book)) .catch ((err) => throw err)) module.exports = router;

Hier gebeurt geen magie.

Ten eerste moeten verzoeken aan deze router een id hebben: de id van het boek. Dit id wordt verkregen uit de params van het verzoek met behulp van req.params.id. Dit wordt gebruikt om het specifieke boek te identificeren dat uit de database moet worden verkregen, omdat de id's uniek zijn. Wanneer het boek is gevonden, wordt de genre-waarde van het boek gevuld met alle genres die zijn opgeslagen in deze boekexemplaar. Als alles goed gaat, wordt de boekweergave weergegeven, anders wordt er een fout gegenereerd.

Laten we de weergave voor een boek maken. Hier is hoe het eruit zou moeten zien.

blokinhoud .well.well-lg h1 # [strong Name:] # book.name ul li # [strong Description:] # book.description li # [strong Author]: # book.author li # [sterk genre:] elk genre in book.genre # genre.name |,

U kunt uw knooppuntserver starten door het uitvoeren van:

DEBUG = tutsplus-bibliotheek: * npm start

Conclusie

Nu weet u hoe u een standaard webtoepassing in Node.js kunt bouwen, niet alleen een eenvoudige taak. U hebt formulierverzending kunnen verwerken, hebt twee modellen kunnen raadplegen en hebt middleware kunnen instellen.

U kunt verder gaan door de toepassing uit te breiden - probeer de mogelijkheid om een ​​boek te verwijderen toe te voegen. Voeg eerst een knop toe aan de showpagina en ga vervolgens naar de routesbestanden en voeg hier een router voor toe. Merk op dat dit een a zal zijn POST verzoek.

U kunt ook meer functies bedenken om aan de toepassing toe te voegen. ik hoop dat je het leuk vond.