Langsung saja ya 😄
Saya ingin berbagi tentang tutorial membuat modular HMVC (Hierarchical Model View Controller). Tutorial ini sebenarnya berdasarkan pada project brizkoder yang kemudian saya modifikasi sendiri. Struktur project yang saya modifikasi menggunakan konsep HMVC yaitu membagi setiap modul project yang di dalamnya terdapat Model, View dan Controller. Seperti berikut ini:
Mungkin saya hanya menjelaskan garis besarnya saja karena saya rasa sudah banyak yang membahas tentang NodeJs & ExpressJS.
server.js untuk mengatur Express Webserver
const express = require("express"); const bodyParser = require("body-parser");const app = express();// parse requests of content-type - application/json app.use(bodyParser.json());// parse requests of content-type - application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: true }));require("./app/config/config.router.js")(app);// set port, listen for requests const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}.`); });
Pada folder config terdapat 2 file yaitu config.db.js dan config.router.js.
config.db.js untuk configurasi DB silahkan sesuaikan sendiri
module.exports = {
HOST: "localhost",
USER: "root",
PASSWORD: "root",
DB: "node-project"
};
config.router.js untuk menangani semua CRUD dari setiap modul
module.exports = app => { app.get("/", (req, res) => { res.json({ message: "Welcome to application." }); });require("../modules/customers/routers/customer.routes.js")(app); };
Di folder core terdapat 2 file yaitu core.connection.js dan core.model.js.
core.connection.js untuk menghubungkan project dengan DB
const mysql = require("mysql"); const dbConfig = require("../config/config.db.js");const connection = mysql.createConnection({ host: dbConfig.HOST, user: dbConfig.USER, password: dbConfig.PASSWORD, database: dbConfig.DB });connection.connect(error => { if (error) throw error; console.log("Successfully connected to the database."); });module.exports = connection;
core.model.js untuk beroperasi dengan DB. Disini saya memodifikasi beberapa baris kode yang nantinya bisa digunakan pada beberapa modul.
//modified by Puguh Jayadiconst connection = require("../core/core.connection.js"); const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000;module.exports = function(table) {return {paginate : function(object, result) { const host = object.protocol+"://"+object.hostname+":"+PORT; const per_page = (object.query.per_page) ? parseInt(object.query.per_page) : 10; const page = (object.query.page) ? parseInt(object.query.page) : 1; const search = (object.query.search) ? object.query.search : ''; const offset = (page - 1) * per_page; const whereLike = this.whereLike(object.column, search); const queryBase = "SELECT * FROM "+table; const queryLimit = queryBase+" WHERE "+ whereLike.columns +" limit "+per_page+" OFFSET "+offset; if(search != ''){ querySearch= queryBase+" WHERE "+whereLike.columns; } else { querySearch= queryBase; }connection.query(querySearch, whereLike.search, (err, rows) => { let tot = parseInt(rows.length); let first_page = 1; let previous_page = page > 0 ? page - 1 : "null"; let next_page = page < Math.ceil(tot / per_page) ? page + 1 : "null"; let last_page = Math.ceil(tot / per_page);connection.query(queryLimit, whereLike.search, (err, res) => { if (err) { console.log("error: ", err); result(err, null); return; }response = { search : search, total : tot, per_page : per_page, previous_page : previous_page, current_page : page, last_page : last_page, first_page_url: host+object.path + "?search="+search+"&page="+first_page+"&per_page="+per_page, last_page_url: host+object.path + "?search="+search+"&page="+last_page+"&per_page="+per_page, previous_page_url: (previous_page != 0) ? host+object.path + "?search="+search+"&page="+previous_page+"&per_page="+per_page : "null", next_page_url: (next_page != "null") ? host+object.path + "?search="+search+"&page="+next_page+"&per_page="+per_page : "null", path : host + object.path, from : offset + 1, to : offset + res.length, data : res }result(null, response); }); }); },all : function(result) { connection.query("SELECT * FROM "+table, (err, res) => { if (err) { console.log("error: ", err); result(err, null); return; } result(null, res); }); },nums : function(result) { connection.query("SELECT COUNT(*) AS nums FROM "+table, (err, res) => { if (err) { console.log("error: ", err); result(err, null); return; } result(null, res); }); },store : function (object, result) { connection.query("INSERT INTO "+table+" SET ?", object, (err, res) => { if (err) { console.log("error: ", err); result(err, null); return; }console.log("created object: ", { id: res.insertId, ...object }); result(null, { id: res.insertId, ...object }); }); },show : function(id, result) { connection.query("SELECT * FROM "+table+" WHERE id = ?", [id], (err, res) => { if (err) { console.log("error: ", err); result(err, null); return; } if (res.length) { console.log("found object: ", res[0]); result(null, res[0]); return; }result(null, { message: "not found" });}); },update : function (id, object, result) { connection.query( "UPDATE "+table+" SET ? WHERE id = ?", [object, id], (err, res) => { if (err) { console.log("error: ", err); result(null, err); return; }if (res.affectedRows == 0) { result(null, { message: "not found" }); return; }console.log("updated object: ", { id: id, ...object }); result(null, { id: id, ...object }); } ); },destroy : function(id, result) { connection.query("DELETE FROM "+table+" WHERE id = ?", id, (err, res) => { if (err) { console.log("error: ", err); result(null, err); return; }if (res.affectedRows == 0) { result(null, { message: "not found" }); return; }console.log("deleted object with id: ", id); result(null, res); }); },whereLike : function(columns, search) { return { columns : columns.join(" LIKE ? OR ")+" LIKE ?", search : Array(columns.length).fill('%'+search+'%') } },} };
Folder customers kita anggap sebagai modul yang didalamnya terdapat folder beberapa folder MVC.
customer.model.js untuk merepresentasikan data customers di DB
const Customer = function(customer) { this.email = customer.email; this.name = customer.name; this.active = customer.active; };Customer.table = "customers";module.exports = Customer;
customer.controller.js untuk melakukan logika dan mengontrol modul
const Customer = require("../models/customer.model.js"); const coreModel = require("../../../core/core.model.js")(Customer.table);// http://localhost:3000/customers?search=ayu&page=3&per_page=3 exports.getAll = (req, res) => { req.column = ["name", "email", "active"];coreModel.paginate(req, (err, data) => { if (err) res.status(500).send({ message: err.message || "Some error occurred while retrieving customers." }); else res.send(data); }); };exports.store = (req, res) => { if (!req.body) { res.status(400).send({ message: "Content can not be empty!" }); } // can custom object const customer = new Customer({ email: req.body.email, name: req.body.name, active: req.body.active });coreModel.store(customer, (err, data) => { if (err) res.status(500).send({ message: err.message || "Some error occurred while creating the Customer." }); else res.send(data); }); };exports.show = (req, res) => { coreModel.show(req.params.customerId, (err, data) => { if (err) { if (err.kind === "not_found") { res.status(404).send({ message: `Not found Customer with id ${req.params.customerId}.` }); } else { res.status(500).send({ message: "Error retrieving Customer with id " + req.params.customerId }); } } else res.send(data); }); };exports.update = (req, res) => { if (!req.body) { res.status(400).send({ message: "Content can not be empty!" }); }coreModel.update( req.params.customerId, new Customer(req.body), (err, data) => { if (err) { if (err.kind === "not_found") { res.status(404).send({ message: `Not found Customer with id ${req.params.customerId}.` }); } else { res.status(500).send({ message: "Error updating Customer with id " + req.params.customerId }); } } else res.send(data); } ); };exports.destroy = (req, res) => { coreModel.destroy(req.params.customerId, (err, data) => { if (err) { if (err.kind === "not_found") { res.status(404).send({ message: `Not found Customer with id ${req.params.customerId}.` }); } else { res.status(500).send({ message: "Could not delete Customer with id " + req.params.customerId }); } } else res.send({ message: `Customer was deleted successfully!` }); }); };
customer.router.js untuk mengontrol proses CRUD modul customers
const customers = require("../controllers/customer.controller.js");module.exports = app => { app.get("/customers", customers.getAll); app.post("/customers", customers.store); app.get("/customers/:customerId", customers.show); app.put("/customers/:customerId", customers.update); app.delete("/customers/:customerId", customers.destroy); };
Silahkan coba dengan aplikasi postman dengan mengetik
node server
kemudian akses URL
http://localhost:3000/customers?search=ayu&page=1&per_page=2
hasilnya kurang lebih seperti ini
Sekian, semoga bermanfaat 😄