CRUD Nuxt Mongo

8 min read


Jadi kali ini saya akan membuat API Server menggunakan NuxtJS dan Express yang mana dalam fitur NuxtJS bisa membuat backend dan fronted berjalan secara bersamaan, yakni express sebagai API dan NuxtJS sebagai frontend menggunakan “serverMiddleware”.

BACKEND

  • Buat Project Baru
npx create-nuxt-app project1

Pilih UI framework : Bootstrap Vue

Pilih custom server framework : Express

Pilih NuxtJS modules : axios

  • Install package
cd project1
npm install express-validator jsonwebtoken mongoose bcryptjs

Penjelasan :

express-validator : untuk validasi data yang di submit oleh form
jsonwebtoken : untuk generate dan verifikasi token login
mongoose : schema based untuk interaksi dengan mongodb
bcryptjs : untuk encode/decode autentikasi token (jsonwebtoken)

  • Configurasi Nuxt

isikan code ini supaya bisa both backend dan frontend pada nuxtconfig.js dijelaskan bahwa server API nya ada di folder /api/index.js

serverMiddleware: [
    '~/api/index.js'
]
  • Mulai implementasinya

/api
–> /controllers – all the business logic for all individual modules
–> /models – create mongodb schema and define them in this folder in separate files for every schema
–> /routes – create API routes for every models created inside /models folder
–> db.js – all the db connection related stuff will be in this file
–> index.js – main file to run the API server
–> config.js – to store and access all global variables & functions. e.g. authentication token, checkAuthenticated() etc.

codingan /api/db.js

const mongoose = require('mongoose');
// mongodb database connection string. change it as per your needs. here "mydb" is the name of the database. You don't need to create DB from mongodb terminal. mongoose create the db automatically.
mongoose.connect('mongodb://localhost/mydb', {
                            useNewUrlParser: true,
                            useUnifiedTopology: true,
                            useFindAndModify: false,
                            useCreateIndex: true
                          });
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
  console.log("MongoDB Connected...");
});

module.exports = db

codingan /api/config.js

const jwt = require('jsonwebtoken');

const config = {
  authSecret:'mysecret', // secret for generating jwt token
}

module.exports = config

// check if user logged in
module.exports.isAuthenticated = function (req, res, next) {
  var token = req.headers.authorization
  if (token) {
    // verifies secret and checks if the token is expired
    jwt.verify(token.replace(/^Bearer\s/, ''), config.authSecret, function(err, decoded) {
      if (err) {
        return res.status(401).json({message: 'unauthorized'})
      } else {
        return next();
      }
    });
  }
  else{
    return res.status(401).json({message: 'unauthorized'})
  }
}

codingan /api/index.js

const express = require('express')
const db = require('./db')


// Create express instnace
const app = express()

// Init body-parser options (inbuilt with express)
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Require & Import API routes
const users = require('./routes/users')
const articles = require('./routes/articles')

// Use API Routes
app.use(users)
app.use(articles)

// Export the server middleware
module.exports = {
  path: '/api',
  handler: app
}
  • Membuat Model Schema
Pada langkah ini kita mendefinisikan skema MongoDB. Paket mongoose membaca kode ini dan membuat skema secara otomatis di dalam MongoDB. Jadi, kita tidak perlu membuat skema apa pun dengan masuk ke MongoDB secara manual.

codingan /api/models/Article.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const Article = new Schema ({
  title: { type: String, required: true, index: { unique: true } },
  author: { type: String, required: true },
  body: { type: String, required: true },
});

module.exports = mongoose.model('Article', Article)

codingan /api/models/User.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const User = new Schema ({
  full_name: { type: String, required: true },
  email: { type: String, required: true, index: { unique: true } },
  password: { type: String, required: true },
});

module.exports = mongoose.model('User', User)
  • Membuat Controller untuk setiap Model

codingan /api/controllers/usersController.js

const config = require('../config')
const User = require('../models/User')
const validator = require('express-validator')
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs')


// Register
module.exports.register = [
  // validations rules
  validator.body('full_name', 'Please enter Full Name').isLength({ min: 1 }),
  validator.body('email', 'Please enter Email').isLength({ min: 1 }),
  validator.body('email').custom(value => {
    return User.findOne({email:value}).then(user => {
      if (user !== null) {
        return Promise.reject('Email already in use');
      }
    })
  }),
  validator.body('password', 'Please enter Password').isLength({ min: 1 }),

  function(req, res) {
    // throw validation errors
    const errors = validator.validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(422).json({ errors: errors.mapped() });
    }

    // initialize record
    var user = new User({
        full_name : req.body.full_name,
        email : req.body.email,
        password : req.body.password,
    })

    // encrypt password
    var salt = bcrypt.genSaltSync(10);
    var hash = bcrypt.hashSync(user.password, salt);
    user.password = hash

    // save record
    user.save(function(err, user){
        if(err) {
            return res.status(500).json({
                message: 'Error saving record',
                error: err
            });
        }
        return res.json({
            message: 'saved',
            _id: user._id
        });
    })
  }
]


// Login
module.exports.login = [
  // validation rules
  validator.body('email', 'Please enter Email').isLength({ min: 1 }),
  validator.body('password', 'Please enter Password').isLength({ min: 1 }),

  function(req, res) {
    // throw validation errors
    const errors = validator.validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(422).json({ errors: errors.mapped() });
    }

    // validate email and password are correct
    User.findOne({email: req.body.email}, function(err, user){
        if(err) {
            return res.status(500).json({
                message: 'Error logging in',
                error: err
            });
        }

        if (user === null) {
          return res.status(500).json({
            message: 'Email address you entered is not found.'
          });
        }

        // compare submitted password with password inside db
        return bcrypt.compare(req.body.password, user.password, function(err, isMatched) {
          if(isMatched===true){
            return res.json({
              user: {
                _id: user._id,
                email: user.email,
                full_name: user.full_name
              },
              token: jwt.sign({_id: user._id, email: user.email, full_name: user.full_name}, config.authSecret) // generate JWT token here
            });
          }
          else{
            return res.status(500).json({
              message: 'Invalid Email or Password entered.'
            });
          }
        });
    });
  }
]

// Get User
module.exports.user = function(req, res) {
  var token = req.headers.authorization
  if (token) {
    // verifies secret and checks if the token is expired
    jwt.verify(token.replace(/^Bearer\s/, ''), config.authSecret, function(err, decoded) {
      if (err) {
        return res.status(401).json({message: 'unauthorized'})
      } else {
        return res.json({ user: decoded })
      }
    });
  }
  else{
    return res.status(401).json({message: 'unauthorized'})
  }
}

codingan /api/controllers/articlesController.js

const Article = require('../models/Article');
const validator = require('express-validator');

// Get all
module.exports.list = function (req, res, next) {
  Article.find({}, function(err, articles){
    if(err) {
        return res.status(500).json({
            message: 'Error getting records.'
        });
    }
    return res.json(articles);
  });
}


// Get one
module.exports.show = function(req, res) {
  var id = req.params.id;
  Article.findOne({_id: id}, function(err, article){
      if(err) {
          return res.status(500).json({
              message: 'Error getting record.'
          });
      }
      if(!article) {
          return res.status(404).json({
              message: 'No such record'
          });
      }
      return res.json(article);
  });
}


// Create
module.exports.create = [
  // validations rules
  validator.body('title', 'Please enter Article Title').isLength({ min: 1 }),
  validator.body('title').custom(value => {
    return Article.findOne({title:value}).then(article => {
      if (article !== null) {
        return Promise.reject('Title already in use');
      }
    })
  }),
  validator.body('author', 'Please enter Author Name').isLength({ min: 1 }),
  validator.body('body', 'Please enter Article Content').isLength({ min: 1 }),

  function(req, res) {
    // throw validation errors
    const errors = validator.validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(422).json({ errors: errors.mapped() });
    }

    // initialize record
    var article = new Article({
        title : req.body.title,
        author : req.body.author,
        body : req.body.body,
    })

    // save record
    article.save(function(err, article){
        if(err) {
            return res.status(500).json({
                message: 'Error saving record',
                error: err
            });
        }
        return res.json({
            message: 'saved',
            _id: article._id
        });
    })
  }
]

// Update
module.exports.update = [
  // validation rules
  validator.body('title', 'Please enter Article Title').isLength({ min: 1 }),
  validator.body('title').custom( (value, {req}) => {
    return Article.findOne({ title:value, _id:{ $ne: req.params.id } })
      .then( article => {
      if (article !== null) {
        return Promise.reject('Title already in use');
      }
    })
  }),
  validator.body('author', 'Please enter Author Name').isLength({ min: 1 }),
  validator.body('body', 'Please enter Article Content').isLength({ min: 1 }),

  function(req, res) {
    // throw validation errors
    const errors = validator.validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(422).json({ errors: errors.mapped() });
    }

    var id = req.params.id;
    Article.findOne({_id: id}, function(err, article){
        if(err) {
            return res.status(500).json({
                message: 'Error saving record',
                error: err
            });
        }
        if(!article) {
            return res.status(404).json({
                message: 'No such record'
            });
        }

        // initialize record
        article.title =  req.body.title ? req.body.title : article.title;
        article.author =  req.body.author ? req.body.author : article.author;
        article.body =  req.body.body ? req.body.body : article.body;

        // save record
        article.save(function(err, article){
            if(err) {
                return res.status(500).json({
                    message: 'Error getting record.'
                });
            }
            if(!article) {
                return res.status(404).json({
                    message: 'No such record'
                });
            }
            return res.json(article);
        });
    });
  }

]


// Delete
module.exports.delete = function(req, res) {
  var id = req.params.id;
  Article.findByIdAndRemove(id, function(err, article){
      if(err) {
          return res.status(500).json({
              message: 'Error getting record.'
          });
      }
      return res.json(article);
  });
}
  • Buat Routes untuk setiap Controller

codingan /api/routes/users.js

const config = require('../config')
const { Router } = require('express')

const router = Router()

// Initialize Controller
const usersController = require('../controllers/usersController')

// Register
router.post('/users/register', usersController.register)

// Login
router.post('/users/login', usersController.login)

// Get User
router.get('/users/user', usersController.user)

module.exports = router

codingan /api/routes/articles.js

const config = require('../config')
const { Router } = require('express')

const router = Router()

// Initialize Controller
const articlesController = require('../controllers/articlesController')

// Get All
router.get('/articles', articlesController.list)

// Get One
router.get('/articles/:id', articlesController.show)

// Create
router.post('/articles', config.isAuthenticated, articlesController.create)

// Update
router.put('/articles/:id', config.isAuthenticated, articlesController.update)

// Delete
router.delete('/articles/:id', config.isAuthenticated, articlesController.delete)

module.exports = router

Perhatikan “config.isAuthenticated” dalam kode ini. Ini adalah middleware yang digunakan untuk mengamankan rute tertentu.

berikut adalah endpointsnya:

[POST] /api/users/register => register user
[POST] /api/users/login => log in user
[GET] /api/users/user => get logged in user details [GET] /api/articles => get all articles
[GET] /api/articles/:id => get single article
[POST] /api/articles => create article
[PUT] /api/articles/:id => update article
[DELETE] /api/articles/:id => delete article

  • Jalankan server
npm run dev

sekarang test endpointnya pakai imsonia dan pastikan sudah sesuai semua.

FRONTEND

  • Install Nuxt Auth Module

Modul Nuxt Auth adalah modul Nuxt resmi yang dapat kita gunakan untuk mengimplementasikan fitur terkait Autentikasi Pengguna.

cd nuxt-with-express
npm install @nuxtjs/auth
  • Konfigurasi Nuxt Modules

taruh didalam /nuxt.config.js untuk mengaktifkan modulenya

modules: [
    'bootstrap-vue/nuxt', // enables bootstrap vue module
    '@nuxtjs/axios', // enables Nuxt Axios module
    '@nuxtjs/auth', // enables Nuxt Auth module
],
  • Konfigurasi Nuxt Auth

tambah lagi didalam file nuxt confignya

auth: {
    strategies: {
		local: {
			endpoints: {
				// these are the API endpoints we created in Express
				login: {
					url: '/api/users/login',
					method: 'post',
					propertyName: 'token'
				},
				logout: true,
				user: {
					url: '/api/users/user',
					method: 'get',
					propertyName: 'user'
				}
			},
			tokenRequired: true,
			tokenType: "Bearer"
		}
    },
    redirect: {
		  login: '/user/login', // User will be redirected to this path if login is required
		  logout: '/', // User will be redirected to this path if after logout, current route is protected
		  home: '/' // User will be redirect to this path after login if accessed login page directly
    },
    rewriteRedirects: true,
},

https://github.com/aslamdoctor/nuxt-with-express/blob/master/layouts/default.vue

Github :

https://github.com/aslamdoctor/nuxt-with-express/tree/master/pages/articles

https://github.com/aslamdoctor/nuxt-with-express/blob/master/pages/index.vue

npm run dev

buka url http://localhost:3000

  • Selesai

Bima Sena
  1. qqojekfxw says:

    Nice!!!

  2. iqrjtdxdwg says:

    CRUD Nuxt Mongo – Kresec ::

  3. bwmzncdows says:

    CRUD Nuxt Mongo – Kresec ::

  4. amexciyub says:

    Great!

  5. ewpeqeluhulel says:

    Great!

  6. qzitahe says:

    Great!

  7. jnidvwe says:

    CRUD Nuxt Mongo – Kresec ::

Leave a Reply

Your email address will not be published. Required fields are marked *