Make a Node.js Web App with User Accounts and Posts using Redis

EDIT:

I now know that this is not really something done, redis is so awesome and fast because it stores everything in ram, so for a production app with thousands of users, it would cost way to much!. Redis is great for some things but for user accounts and information like posts and blogs I have moved to mongodb and have started learning about that.

I will be adding a finished version to my GitHub with css and all.

I wanted a tutorial for making a fully functional blog web app with user accounts and all, the only one I could find was for PHP but I wanted it for node!. So I figured once I figured it out I would make a post about it, so here it goes…

First off, I want to assume you know what node, npm, redis, express, and pug are. I will go through in enough detail so you don’t need to know much but a bit of practice with these things will help you follow this.

For links to awesome places to learn more about the tools used in this tutorial check out this page.. Awesome Tools For This Tutorial

If you do not know how to set up a node web app environment, I am going to write a tutorial about that but there are a few out there. Maybe sign up for a CodeAnywhere or a Cloud9 account and start a new node container.

Step One

Make your root folder and name it something awesome like blog, cd into it from your terminal and type npm init then press enter. If you have not already install nodemon by typing npm install nodemon.This creates a package.json file for use, then we can install our dependencies. Next in the terminal type npm install express pug redis body-parser cookie-parser --save, this will install all we need and add a “node-modules” folder to out root dir. The last part of this step is to create some empty files and folders. In terminal type mkdir views routes public, then touch app.js views/layout.pug views/home.pug views/login.pug views/sign-up.pug public/main.css public/main.js routes/home.js routes/login.js routes/sign-up.js, this gives us a good place to start.

One more thing… get the latest copy of jquery and place it in your public folder. This will only be used for the ajax request.

Step Two

Open app.js in the editor, in this file we are going to add our modules and routes.

var app = require('express')();app.set('view engine', 'pug');
app.use(require('cookie-parser')());
app.use(require('body-parser').json());
app.use(require('body-parser').urlencoded({extended:true}));
app.use(require('express').static(__dirname + "/public"));
app.listen(8080);
app.use('/', require('./routes/home'));
app.use('/sign-up', require('./routes/sign-up'));
app.use('/login', require('./routes/login'));

That is all for now, all of the magic will happen on the other files.

Do not forget the . at the beginning of the module path, this tells node to use the current directory, if you use .. it will point to the current directory’s root folder.

Step Three

Okay let’s really quick set up some basic files and test to make sure everything is working.

Open your routes folder and one by one add the following code to each file, only changing 'name' to the filename, expample res.render('name', {title: 'name'}); becomes res.render('home', {title: 'home'}); for the home.js file.

var router = require('express').Router();router.get('/', function(req, res){
res.render('name', {title: 'name'});
});
module.exports = router;

Next we need to set up our views, go into your views folder and open the file layout.pug . This file has the setup and the rest “extend” this file.

doctype html
html
head
title=title
link(rel="stylesheet" href="main.css")
script(src="jquery-3.2.1.js")
script(src="main.js")
body
nav
a(href="/") home
a(href="/login") login
a(href="/sign-up") sign-up
a(href="/logout") logout

block home
block sign-up
block login

That is it for the layout for now, the rest of the files all get the following again change name to the file name, block name becomes block home for home.pug.

extends layout
block name
h1=title

Pug uses tabs or spaces to keep track of things since there are no closing brackets, it is a pretty amazingly awesome template engine and you can even practice it on CODEPEN

Everything is now in place, or it should be…. Open your terminal and type nodemon index.js this will start your app, if you don’t get any errors point a new tab to your server address and port ie. http://localhost:8080 and you should see your site! YAY! hopefully!

If you go get an error try to figure it out, if you are new to coding, expect errors always and forever! If you are not new then you already know…

Step Four

Now that we have a working running very simple web app that could be anything at all, let’s make our sign up page, the first step for any user will be to make an account.

The first part of part four is to open our sign-up.pug file and add a form to it, so…

extends layout
block sign-up
h1=title
form(method="POST")
input(type="text" name="username" placeholder="username")
input(type="password" name="password" placeholder="password")
input(type="email" name="email" placeholder="email")
input(type="hidden" name="date" id="date")
input(type="submit" name="submit" onclick="getdate()")

script.
function getdate(){
var date = new Date();
document.getElementById('date').value = date.getTime();
}

After we set this up we can open up our route file sign-up.js . For a check lets console.log the results of the form on the server side.

var router = require('express').Router();router.get('/', function(req, res){
res.render('sign-up', {title: 'sign-up'});
});
router.post('/', function(req, res){
var new_user = {
username: req.body.username,
password: req.body.password,
email: req.body.email,
date: req.body.date
}
console.log(new_user);
res.send("check your console");
});
module.exports = router;

If you go to your site and submit the form on the sign-up page, the page goes to just a white page with “check your console”, and if you check your terminal on the server side you will see the info entered on the form. Pretty neat.

Now lets get out hands dirty with some redis and make this account real.. Add the redis client module to the sign-up.js file, like this…

var router = require('express').Router(),
client = require('redis').createClient();

Then lets add a place for the form to send back information, like if something goes wrong, this is a two step process…

//This happens at the top of the file at the get not the postrouter.get('/', function(req, res){
var msg = req.query.msg;
res.render('sign-up', {
title: 'sign-up',
msg: msg
});
});
// Then go to the sign-up.pug file and add this after h1=title
h1=title
h3(style="color: red;")=msg

first I will show you the code and try to explain…

var router = require('express').Router(),
client = require('redis').createClient();

router.get('/', function(req, res){
var msg = req.query.msg;
res.render('sign-up', {
title: 'sign-up',
msg: msg
});
});
router.post('/', function(req, res){
var new_user = {
username: req.body.username,
password: req.body.password,
email: req.body.email,
date: req.body.date
}
client.hget('users', new_user.username, function(err, id){
if(id !== null){
res.redirect('/sign-up?msg=Username Unavailable');
} else {
client.incr('new_user_id', function(err, user_id){
client.hmset('user:' + user_id, new_user);
client.hset('users', new_user.username, user_id);
})
}
})
});
module.exports = router;

So if you are unfamiliar with redis this might be confusing. The first part, client.hget('users', new_user.username part is asking redis id the username entered is already being used, if it is then the page is reloaded with the error msg Username Unavailable . Then we get the new user a new user_id using incr . After that we set up the main user hash and then set a way to get the user_id from the username using another hash. Bam! Last we send an OK status and redirect to the login page where the new user can login for the first time.

Step Five

Let us login my friends…

First thing to do here is add that place for a message and a form to login, so open the login.pug file…

extends layout
block login
h1=title
h3(style="color: red;")=msg

form(method="POST")
input(type="text" name="username" placeholder="username")
input(type="password" name="password" placeholder="password")
input(type="submit" value="Login")

Then let’s open the login.js file and add the redis client as well as a post function to catch '/' .

var router = require('express').Router(),
client = require('redis').createClient();
router.get('/', function(req, res){
res.render('login', {title: 'login'});
});
router.post('/', function(req, res){
var username = req.body.username;
var password = req.body.password;
if(password == "" || username == ""){
res.redirect('/login?msg=Please Fill Both Username and Password');
} else {
var check = client.hget('users', username, function(err, user_id){
if(!check) {
res.redirect('/login?msg=Wrong Username or Password');
} else {
client.hget('user:' + user_id, 'password', function(err, pass) {
if(pass !== password) {
res.redirect('/login?msg=Wrong Username or Password');
} else {
var cookie = Math.random().toString().replace('.', '');
client.hset('user:' + user_id, 'auth', cookie);
client.hset('auths', cookie, user_id);
res.cookie('auth', cookie).redirect('/');
}
})
}
})
}
})
module.exports = router;

There is quite a bit here but it is pretty simple. First we get the username and password the user entered, then check if the username is found, if so then check to see if that password match the one for that username, if so, then make a random number and give it to that user as well as the users computer, as long as the cookie matches the user is logged in.

This is simply for the purpose of learning, this is no where near enough security for an actual web app, so maybe look into that

Step Six

After this step the basic login and logout will be setup. We will now be working on the home page. This page will check if you are logged in and if so, show you your information, otherwise, return to the login page. Let’s Go!

extends layout
block home
h1=title
h3 username: #{username}
input(type="hidden" value=date id="d")
h3(id="time")
h3 email: #{email}

script.
var date = new Date(eval(document.getElementById('d').value));
document.getElementById('time').innerHTML = "User signed up on: " + date;

That takes care of the view home.pug, now lets work on home.js

var router = require('express').Router(),
client = require('redis').createClient();
router.get('/', function(req, res){
var cookie = req.cookies.auth;
if(cookie === undefined){
res.redirect('/login?msg="Please Login"');
} else {
var check = client.hget('auths', cookie, function(err, user_id){
if(!check){
res.clearCookie('auth').redirect('/login?msg=Please Login');
} else {
client.hget('user:' + user_id, 'auth', function(err, auth){
if(auth !== cookie){
res.clearCookie('auth').redirect('/login?msg=Please Login');
} else {
client.hgetall('user:' + user_id, function(err, data){
res.render('home', {
title: 'home',
username: data.username,
date: data.date,
email: data.email
});
})
}
})
}
})
}
});
module.exports = router;

The first thing we do is get the cookie from login and make sure it still holds up, then we double check it because why not, from there if all is good we get all the user data with client.hgetall and then render it to the page. Awesome!

The last step to all this, logout.. This is a pretty tough thing to do, open up your main index.js file and add app.get('/logout', function(req, res){ res.clearCookie('auth').redirect('/login?msg=Logged Out');}); So it looks like this

var app = require('express')();app.set('view engine', 'pug');
app.use(require('cookie-parser')());
app.use(require('body-parser').json());
app.use(require('body-parser').urlencoded({extended:true}));
app.use(require('express').static(__dirname + "/public"));
app.listen(8080);
app.use('/', require('./routes/home'));
app.use('/sign-up', require('./routes/sign-up'));
app.use('/login', require('./routes/login'));
app.get('/logout', function(req, res){
res.clearCookie('auth').redirect('/login?msg=Logged Out');
});

Okay so now, you can make a new user, login and logout, what more could you want to know? How about how to make blog post using ajax post request? If so keep on keeping on, this would be a good time to take a break though. Good job!

Hopefully I get this finished soon.

--

--

--

I can't find anything, all I do is look and look. By the time I found that one thing, that other thing I was holding, it's lost... :wq

Love podcasts or audiobooks? Learn on the go with our new app.

Why I Choose React

Javascript List

V8 engine, Ember.js and Node Releases — Frontend News #14 | frontendhouse.com

NaA Complete Guide to know about React Native Latest Version 0.60

Build your own Rubik’s Cube with WebGL

Troubleshooting Angular routing

criminal girl with Angular logo

Authentication with AccountsJS & GraphQL Modules

Mastering the Angular performance — by dropping the magic of Change Detector

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Daniel Jordan Osborn

Daniel Jordan Osborn

I can't find anything, all I do is look and look. By the time I found that one thing, that other thing I was holding, it's lost... :wq

More from Medium

NodeJS Features & Benefits: How to Develop NodeJS Apps Faster?

NodeJS Features & Benefits: How to Develop NodeJS Apps Faster?

Mongoose, an ORM (Object-relational mapping), is a fantastic NPM(Node Package Manager) library.

Push Strapi to Heroku Using Github Repository