Project Summary
In this project, we will take the afternoon project of the first day of Node and modify it to use sessions
, custom middleware
, and also use query parameters
. We'll build a filter middleware that will censor words before being pushed to the messages
array. We'll also modify the update
and delete
endpoints to use query parameters
instead of URL parameters. Lastly, we'll use sessions
to keep track of messages sent by a user during a session and build out an endpoint that will display the history of messages.
Live Example
Setup
- Fork and clone this repository.
cd
into the project.- Run
npm install
.
Step 1
Summary
In this step, we'll use npm
to install express-session
and dotenv
, require them in our server/index.js
, and configure our app to use sessions
.
Instructions
- Run
npm install --save express-session
. - Open
server/index.js
and requireexpress-session
in a variable calledsession
. - Configure the app to use sessions using
app.use
.- The first parameter should be
session
invoked with an object as its first argument. - In the object define the value for
secret
,resave
,saveUninitialized
, andcookie.maxAge
.cookie.maxAge
should be set to the value of10000
.- Don't forget to configure
dotenv
to use with your session secret and include your.env
file in your.gitignore
.
- Don't forget to configure
- The first parameter should be
Solution
server/index.js
const express = require('express');
const bodyParser = require('body-parser');
const session = require('express-session');
const mc = require( `./controllers/messages_controller` );
require('dotenv').config()
const app = express();
app.use( bodyParser.json() );
app.use( express.static( `${__dirname}/../build` ) );
app.use( session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 10000 }
}));
app.post( "/api/messages", mc.create );
app.get( "/api/messages", mc.read );
app.put( "/api/messages", mc.update );
app.delete( "/api/messages", mc.delete );
const port = 1337
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
Step 2
Summary
In this step, we'll create custom middleware that will check to see if the session has a user
object. If it doesn't, we'll add a user object that has a messages
array on it.
Instructions
- Create a folder called
middlewares
inserver/
. - Create a file called
session
inserver/middlewares/session.js
. - Open
server/middlewares/session.js
. - Use
module.exports
to export a function with areq
,res
, andnext
parameter. - Inside the function check if
req.session
has a user property, if it doesn't add a user property that equals an object with amessages
array on it. - After the if statement, call
next
. - Open
server/index.js
. - Require
server/middlewares/session.js
in a variable calledcreateInitialSession
. - Tell
app
to use thecreateInitalSession
middleware after sessions are setup.
Solution
server/middlewares/session.js
module.exports = function( req, res, next ) {
const { session } = req;
if ( !session.user ) {
session.user = {
messages: []
};
}
next();
}
server/index.js
const express = require('express');
const bodyParser = require('body-parser');
const session = require('express-session');
const mc = require( `./controllers/messages_controller` );
require('dotenv').config()
const createInitialSession = require( `./middlewares/session.js` );
const app = express();
app.use( bodyParser.json() );
app.use( express.static( `${__dirname}/../build` ) );
app.use( session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 10000 }
}));
app.use( createInitialSession );
app.post( "/api/messages", mc.create );
app.get( "/api/messages", mc.read );
app.put( "/api/messages", mc.update );
app.delete( "/api/messages", mc.delete );
const port = 1337
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
Step 3
Summary
In this step, we will create a filter middleware file that will handle filtering messages with profanity.
Instructions
- Create a file called
filter.js
inserver/middlewares/
. - Open
server/middlewares/filter.js
. - At the very top of the file create an array called
notAllowed
that contains words that should be censored. - Use
module.exports
to export a function that has areq
,res
, andnext
parameter. - Copy in the following filter code:
-
filter logic
while ( notAllowed.find( word => req.body.text.includes(word) ) ) { const badWord = notAllowed.find( word => req.body.text.includes(word) ); req.body.text = req.body.text.replace( badWord, '*'.repeat( badWord.length ) ); }
-
- Call
next
after thewhile
loop.
Solution
server/middlewares/filter.js
const notAllowed = [ 'poo', 'butt' ];
module.exports = function( req, res, next ) {
while ( notAllowed.find( word => req.body.text.includes(word) ) ) {
const badWord = notAllowed.find( word => req.body.text.includes(word) );
req.body.text = req.body.text.replace( badWord, '*'.repeat( badWord.length ) );
}
next();
};
Step 4
Summary
In this step, we'll require server/middlewares/filter.js
in server/index.js
and check if the method of the request is POST
or PUT
. If it is POST
or PUT
, we'll call our filter
middleware to filter
the text
from the request
body.
Instructions
- Open
server/index.js
. - Require
server/middlewares/filter.js
in a variable calledfilter
. - Add middleware to app that captures
req
,res
, andnext
. - Check if the method of the request is
POST
orPUT
. If it isPOST
orPUT
, callfilter
withreq
,res
, andnext
as arguments. Otherwise just invokenext
.- The method of a request is defined on
req.method
.
- The method of a request is defined on
Solution
server/index.js
const express = require('express');
const bodyParser = require('body-parser');
const session = require('express-session');
const mc = require( `./controllers/messages_controller` );
require('dotenv').config()
const createInitialSession = require( `./middlewares/session.js` );
const filter = require( `./middlewares/filter.js`);
const app = express();
app.use( bodyParser.json() );
app.use( express.static( `${__dirname}/../build` ) );
app.use( session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 10000 }
}));
app.use( createInitialSession );
app.use( ( req, res, next ) => {
const { method } = req;
if ( method === "POST" || method === "PUT" ) {
filter( req, res, next );
} else {
next();
}
});
app.post( "/api/messages", mc.create );
app.get( "/api/messages", mc.read );
app.put( "/api/messages", mc.update );
app.delete( "/api/messages", mc.delete );
const port = 1337
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
Step 5
Summary
In this step, we'll update the messages
controller to add new messages to a user's session and modify the update
and delete
methods to use query parameters
instead. We'll also add a history
endpoint that will allow us to see messages on the session.
Instructions
- Open
server/controllers/messages_controller.js
. - Modify the
create
method to add the new message object to themessages
array on session as well. - Modify the
update
method to useid
off therequest
query. - Modify the
delete
method to useid
off therequest
query. - Create a
history
method that will return allmessages
on a user's session. - Open
server/index.js
. - Create a
GET
endpoint at/api/messages/history
that calls thehistory
method from themessages
controller.
Solution
server/controllers/messages_controller.js
let messages = [];
let id = 0;
module.exports = {
create: ( req, res ) => {
const { text, time } = req.body;
const { user } = req.session;
messages.push({ id, text, time });
user.messages.push({ id, text, time });
id++;
res.status(200).send( messages );
},
read: ( req, res ) => {
res.status(200).send( messages );
},
update: ( req, res ) => {
const { text } = req.body;
const updateID = req.query.id;
const messageIndex = messages.findIndex( message => message.id == updateID );
let message = messages[ messageIndex ];
messages[ messageIndex ] = {
id: message.id,
text: text || message.text,
time: message.time
};
res.status(200).send( messages );
},
delete: ( req, res ) => {
const deleteID = req.query.id;
messageIndex = messages.findIndex( message => message.id == deleteID );
messages.splice(messageIndex, 1);
res.status(200).send( messages );
},
history: ( req, res ) => {
const { user } = req.session;
res.status(200).send( user.messages );
}
};
server/index.js
const express = require('express');
const bodyParser = require('body-parser');
const session = require('express-session');
const mc = require( `./controllers/messages_controller` );
require('dotenv').config()
const createInitialSession = require( `./middlewares/session.js` );
const filter = require( `./middlewares/filter.js`);
const app = express();
app.use( bodyParser.json() );
app.use( express.static( `${__dirname}/../build` ) );
app.use( session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 10000 }
}));
app.use( ( req, res, next ) => createInitialSession( req, res, next ) );
app.use( ( req, res, next ) => {
const { method } = req;
if ( method === "POST" || method === "PUT" ) {
filter( req, res, next );
} else {
next();
}
});
app.post( "/api/messages", mc.create );
app.get( "/api/messages", mc.read );
app.put( "/api/messages", mc.update );
app.delete( "/api/messages", mc.delete );
app.get( "/api/messages/history", mc.history );
const port = 1337
app.listen( port, () => { console.log(`Server listening on port ${port}.`); } );
Step 6
Summary
In this step, we'll use the front-end
to see if the history
endpoint is working.
Instructions
- Use
nodemon
ornode index.js
when inserver/
to start the server. - Go to
localhost:3000
in your browser. - Send some messages and then check the history.
- Wait 10 seconds and re-check the history.
- The history should now be blank since the session has been set to expire in 10 seconds.
- To refresh the history, toggle it off and on.
Solution
Contributions
If you see a problem or a typo, please fork, make the necessary changes, and create a pull request so we can review your changes and merge them into the master repo and branch.
Copyright
© DevMountain LLC, 2017. Unauthorized use and/or duplication of this material without express and written permission from DevMountain, LLC is strictly prohibited. Excerpts and links may be used, provided that full and clear credit is given to DevMountain with appropriate and specific direction to the original content.