📜 ⬆️ ⬇️

Making a project on Node.js using Mongoose, Express, Cluster. Part 2.1

Introduction


Hello, dear habrovchane! Today we will mainly have small changes, but many changes. In this part we will:



Logs


For logs we will use a homemade module. Create a folder logger . It will have an index.js file.


 var stackTrace = require('stack-trace'); //      var util = require('util'); //util.inspect() var path = require('path'); //path.relative() path.sep var projectname = require('../package').name; //package.json -> project name module.exports = class Logger //   :) { constructor() { function generateLogFunction(level) //     :) { return function(message,meta) { //var d = Date.now(); //      var mes = this.module + " -- "; mes += level + " -- "; mes += message; //   if(meta) mes += " " + util.inspect(meta) + " "; //    (Object||Error) mes += '\n'; //   :) this.write(mes); //       } }; this.trace = stackTrace.get()[1]; //    this.filename = this.trace.getFileName(); //       this.module = projectname + path.sep + path.relative('.',this.filename); //    this.streams = [process.stdout]; //        //        this.log = generateLogFunction('Log'); //   this.info = generateLogFunction('Info'); //   this.error = generateLogFunction('Error'); //   this.warn = generateLogFunction('Warning'); //   } write(d) { this.streams.forEach((stream)=>{ stream.write(d); }); } } 

And now about the syntax of use.


 var logger = new require('./logger')(); //... logger.info('Hello, world'); 

Why do we use new ? In order to get the name of the file in which the logger was created. Because running stack-trace every time we write to the log will use a lot of resources. Replace all console with logger. I will leave everything to the will of your IDE :)


NOTE: In the doc and node_modules there are files using the console . Be careful!


Also replace in the file worker.js console.error with a throw . Like this:


 app.listen(3000,function(err){ if(err) throw err; //       logger.log(`Running server at port 3000!`) //         //      }); 

Why we do not use winston and other modules to work with logs? The answer is simple: winston shows little performance. And not only Winston. The same goes for many modules. As it turned out after some testing, our homemade module shows 4-8 times more performance than many other modules :)


Request processing time


In order to see which requests came to the server and how long it took to process it, we will write our middleware. In the bin folder, create the rt.js file


 var Logger = require('../logger'); var logger = new Logger(); module.exports = function(req,res,next) { //   var beginTime = Date.now(); //    res.on('finish',()=>{ var d = Date.now();//     logger.log('Reponse time: ' + (d - beginTime),{ url:req.url, //       ( urlencode string :) time:(d - beginTime) //    }); }); //     next(); } 

And in worker.js before any handlers, add:


 //   app.use(require('./rt')); 

Here we use our own module because all other modules are NOT able to log only guaranteed requests (at least before the OS) requests.


The difference of the application from the router


In the controller, we saw express() for creating a mini application and then we mounted it into the project using app.use() but express does not recommend doing so. We will replace express() with new express.Router() in the controller file:


 // : var Router = require('express').Router; var app = new Router(); // app.use(....) // app.get(....) // etc 

What problems will arise with express() ? The most important. We cannot change the settings in the entire application. Also, we can't use app.locals . And for some unclear reason, it DOES NOT pass on cookies (Why is this?).


Configuration


Create a folder config . In the folder we will have the index.js file, where we will receive all the settings, add, parse and even rob cows insert, if necessary, the required fields if they are missing.


 module.exports = require('./config'); 

And in the config.json file:


 { "port":8080, "mongoUri":"mongodb://127.0.0.1/armleo-test" } 

NOTE: If there are no enabled networks in windows, then localhost does not work and 127.0.0.1 must be used.
In the worker.js file worker.js add at the beginning:


 var config = require('../config'); 

And the last lines turn into a hare following:


 //     3000      . //  Worker-        app.listen(config.port,function(err){ if(err) throw err; //       logger.log(`Running server at port ${config.port}!`); //         //      }); 

We remember that we still need to change the lines in dbinit.js ? So do it.


 // 10 line bin/dbinit.js //    MongoDB var config = require('../config'); mongoose.connect(config.mongoUri,{ server:{ poolSize: 10 //      // 10     . //      ... } }); 

ES6


We will replace all the necessary var with const and let . A little change, but I like it!


Authorization


Now to the authorization! For authorization we will use Passport.js . In our project, BYE, registration is not needed because one user will be added by us to the database manually. Create the auth.js controller. In the controller, we need input parsers:


 let app = new (require('express').Router)(); const models = require('./../models'); const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; app.use(passport.initialize()); app.use(passport.session()); passport.use(new LocalStrategy( function(username, password, done) { models.User.findOne({ username: username }, function (err, user) { if (err) { return done(err); } if (!user) { return done(null, false, { message: 'Incorrect username.' }); } if (user.password != password) { return done(null, false, { message: 'Incorrect password.' }); } return done(null, user); }); } )); passport.serializeUser(function(user, done) { done(null, user._id); }); passport.deserializeUser(function(id, done) { models.User.findById(id, function(err, user) { done(err, user); }); }); app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }) ); app.get('/login',function(req,res,next) { if(req.user) return res.redirect('/'); res.render('login',{ user:req.user }); }); module.exports = app; 

For authorization, we views/login.html add a form to views/login.html .


 <form action="/login" method="POST"> <input name="username"/> <br/> <input name="password"/> <br/> <input type="submit"/> </form> 

For users we come up with a model.


Posts!


Install the modules:


 npm i mongoose-url-slugs --save 

Create a post model in the models folder file post.js :


 //  mongoose ..          const mongoose = require('mongoose'); const URLSlugs = require('mongoose-url-slugs'); //   ! let postSchema = new mongoose.Schema({ title:{ type:String, // : String required:[true,"titleRequired"], //   .        titleRequired //   32   (Unicode symbol != byte) minlength:[6,"tooShort"], unique:true //     }, text:{ type:String, //  String required:[true,"textRequired"] //      }, //     ,       ! //   //  //   // slug:String }); //    ( ) //      postSchema.plugin(URLSlugs('title')); //     module.exports = mongoose.model('Post',postSchema); 

And in the models/index.js :


 module.exports = { //    () //  *nix-      User:require('./user'), Post:require('./post') }; //     ! 

Create a controller for creating / editing posts! In the file controllers/index.js :


 const Logger = require('../logger'); const logger = new Logger(); let app = new (require('express').Router)(); app.use(require('./auth')); app.use(require('./home')); app.use(require('./post')); module.exports = app; 

And in the file controllers/post.js :


 let app = new (require('express').Router)(); const models = require("../models"); app.get('/post', function(req,res,next) { if(!req.user) return res.redirect('/login'); res.render('addpost',{ user:req.user }); }); app.post('/post', function(req, res, next) { if(!req.user) return res.redirect('/login'); let post = new models.Post(req.body); post.save() .then(()=>{ res.redirect('/post/' + post.slug); }).catch(next); }); app.get('/post/:slug',(req, res, next)=>{ models.Post.findOne({ slug:req.params.slug }).exec().then((post)=>{ if(!post) res.redirect('/#notfound'); res.render('post',{ user:req.user, post }); }).catch(next); }); module.exports = app; 

And accordingly the images! Creations views/addpost.html


 <form method="POST" action="/post"> <input name="title"/> <br/> <input name="text"/> <br/> <input type="submit"/> </form> 

views/post.html


 {{#post}} <h1>{{title}}</h1> <br/> {{text}} {{/post}} 

Let's finish the image views/index.html bit


 {{#user}} Hello {{username}} {{/user}} {{^user}} Login <a href="/login">here!</a> {{/user}} {{#posts}} <br/><a href="/post/{{slug}}">{{title}}</a> {{/posts}} 

Let's finish the controller controllers/home.js :


 let app = new (require('express').Router)(); const models = require('../models'); app.get('/',(req,res,next)=>{ //  handler     `/` models.Post.find({}).exec().then((posts)=>{ res.render('index',{ user:req.user, posts }); //      index }).catch(next); }); module.exports = app; 

Add the urlencode parser to bin/worker.js :


 app.use(bodyParser.urlencoded()); 

Github


You can find our project on the githaba here.


The end of the second part!


At the end of the second part. In the next parts, we will allocate some HTTPS time, services in Ubuntu, We will hash the password, Captcha (recaptcha) and comments with some statistics and introduce markdown support for posts, Replace MongoDB for sessions with Redis, Add caching.


')

Source: https://habr.com/ru/post/314560/


All Articles