How to do it...

Firstly, create a file named server.js that will include two middleware functions. One that configures a session and the other that makes sure that there is a connection to the MongoDB before allowing any route to be called. Then, we mount our API routes to a specific path:

  1. Create a new file named server.js
  2. Include the required libraries. Then, initialize a new ExpressJS application and create a connection to MongoDB:
      const mongoose = require('mongoose') 
      const express = require('express') 
      const session = require('express-session') 
      const bodyParser = require('body-parser') 
      const MongoStore = require('connect-mongo')(session) 
      const api = require('./api/controller') 
      const app = express() 
      const db = mongoose.connect( 
          'mongodb://localhost:27017/test' 
      ).then(conn => conn).catch(console.error) 
  1. Use the body-parser middleware to parse the request body as JSON:
      app.use(bodyParser.json()) 
  1. Define an ExpressJS middleware function that will ensure your web application is connected to MongoDB first before allowing next route handlers to be executed:
      app.use((request, response, next) => {
Promise.resolve(db).then(
(connection, err) => (
typeof connection !== 'undefined'
? next()
: next(new Error('MongoError'))
)
)
})
  1. Configure express-session middleware to store sessions in the Mongo database instead of storing in memory:
      app.use(session({ 
          secret: 'MERN Cookbook Secrets', 
          resave: false, 
          saveUninitialized: true, 
          store: new MongoStore({ 
              collection: 'sessions', 
              mongooseConnection: mongoose.connection, 
          }), 
      })) 
  1. Mount the API controller to the "/api" route:
      app.use('/users', api) 
  1. Listen on port 1773 for new connections:
      app.listen( 
          1337, 
          () => console.log('Web Server running on port 1337'), 
      ) 
  1. Save the file

Then, create a new directory named api. Next, create the model or business logic of your application. Define a schema for users with static and instance methods that will allow a user to signup, login, logout, get profile data, change their password, and remove their profile:

  1. Create a new file named model.js in the api directory
  2. Include the Mongoose NPM module and also the crypto NodeJS module that will be used to generate a hash for the user passwords:
      const { connection, Schema } = require('mongoose') 
      const crypto = require('crypto') 
  1. Define the schema:
      const UserSchema = new Schema({ 
          username: { 
              type: String, 
              minlength: 4, 
              maxlength: 20, 
              required: [true, 'username field is required.'], 
              validate: { 
                  validator: function (value) { 
                      return /^[a-zA-Z]+$/.test(value) 
                  }, 
                  message: '{VALUE} is not a valid username.', 
              }, 
          }, 
          password: String, 
      }) 
  1. Define a static model method for login:
      UserSchema.static('login', async function(usr, pwd) { 
          const hash = crypto.createHash('sha256') 
              .update(String(pwd)) 
          const user = await this.findOne() 
              .where('username').equals(usr) 
              .where('password').equals(hash.digest('hex')) 
          if (!user) throw new Error('Incorrect credentials.') 
          delete user.password 
          return user 
      }) 
  1. Define a static model method for signup:
      UserSchema.static('signup', async function(usr, pwd) { 
          if (pwd.length < 6) { 
              throw new Error('Pwd must have more than 6 chars') 
          } 
          const hash = crypto.createHash('sha256').update(pwd) 
          const exist = await this.findOne() 
              .where('username') 
              .equals(usr) 
          if (exist) throw new Error('Username already exists.') 
          const user = this.create({ 
              username: usr, 
              password: hash.digest('hex'), 
          }) 
          return user 
      }) 
  1. Define a document instance method for changePass:
      UserSchema.method('changePass', async function(pwd) { 
          if (pwd.length < 6) { 
              throw new Error('Pwd must have more than 6 chars') 
          } 
          const hash = crypto.createHash('sha256').update(pwd) 
          this.password = hash.digest('hex') 
          return this.save() 
      }) 
  1. Compile the Mongoose schema into a model and export it:
      module.exports = connection.model('User', UserSchema) 
  1. Save the file

Finally, define a controller that will transform the request body to actions that our model can understand. Then export it as an ExpressJS router that contains all API paths:

  1. Create a new file named controller.js in the api folder
  2. Import model.js and initialize a new ExpressJS Route:
      const express = require('express') 
      const User = require('./model') 
      const api = express.Router() 
  1. Define a request handler to check if a user is logged in and another request handler to check if the user is not logged in:
      const isLogged = ({ session }, res, next) => { 
          if (!session.user) res.status(403).json({ 
              status: 'You are not logged in!', 
          }) 
          else next() 
      } 
      const isNotLogged = ({ session }, res, next) => { 
          if (session.user) res.status(403).json({ 
              status: 'You are logged in already!', 
          }) 
          else next() 
      } 
  1. Define a post request method to handle requests to "/login" endpoint:
      api.post('/login', isNotLogged, async (req, res) => { 
          try { 
              const { session, body } = req 
        const { username, password } = body 
              const user = await User.login(username, password) 
              session.user = { 
                  _id: user._id, 
                  username: user.username, 
              } 
              session.save(() => { 
                  res.status(200).json({ status: 'Welcome!'}) 
              }) 
          } catch (error) { 
              res.status(403).json({ error: error.message }) 
          } 
      }) 
  1. Define a post request method to handle requests to "/logout" endpoint:
      api.post('/logout', isLogged, (req, res) => { 
          req.session.destroy() 
          res.status(200).send({ status: 'Bye bye!' }) 
      }) 
  1. Define a post request method to handle requests to "/signup" endpoint:
      api.post('/signup', async (req, res) => { 
          try { 
              const { session, body } = req 
              const { username, password } = body 
              const user = await User.signup(username, password) 
              res.status(201).json({ status: 'Created!'}) 
          } catch (error) { 
              res.status(403).json({ error: error.message }) 
          } 
      }) 
  1. Define a get request method to handle requests to "/profile" endpoint:
      api.get('/profile', isLogged, (req, res) => { 
          const { user } = req.session 
          res.status(200).json({ user }) 
      }) 
  1. Define a put request method to handle requests to "/changepass" endpoint:
      api.put('/changepass', isLogged, async (req, res) => { 
          try { 
              const { session, body } = req 
              const { password } = body 
              const { _id } = session.user 
              const user = await User.findOne({ _id }) 
              if (user) { 
                  await user.changePass(password) 
                  res.status(200).json({ status: 'Pwd changed' }) 
              } else { 
                  res.status(403).json({ status: user }) 
              } 
          } catch (error) { 
              res.status(403).json({ error: error.message }) 
          } 
      }) 
  1. Define a delete request method to handle requests to "/delete" endpoint:
      api.delete('/delete', isLogged, async (req, res) => { 
          try { 
              const { _id } = req.session.user 
              const user = await User.findOne({ _id }) 
              await user.remove() 
              req.session.destroy((err) => { 
                  if (err) throw new Error(err) 
                  res.status(200).json({ status: 'Deleted!'}) 
              }) 
          } catch (error) { 
              res.status(403).json({ error: error.message }) 
          } 
      }) 
  1. Export the route:
      module.exports = api 
  1. Save the file
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.244.187