วันจันทร์ที่ 8 เมษายน พ.ศ. 2562

การสร้าง Restful API สำหรับการเข้าถึงฐานข้อมูล (Express.js & Node.js)


ในบทความนี้จะเป็นวิธีการสร้าง Restful API ที่มีหน้าที่ให้ Front-end (Angular) เรียกใช้งานเพื่อเข้าถึงฐานข้อมูลในรูปแบบการทำงานต่างๆ

ซึ่งไฟล์หลักๆที่จะกล่าวถึงในบทความนี้ก็คือ app.js และ api.js (/routes/api.js)


app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser')
var logger = require('morgan');
var favicon = require('serve-favicon');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var apiRouter = require('./routes/api').router;

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(bodyParser.text())
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(favicon(__dirname + '/public/images/favicon.ico'));

app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/api', apiRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

ไฟล์นี้จะเป็นไฟล์หลักในการทำงานของ Express (เฉพาะการประกาศการใช้งาน router และ module ต่างๆที่จำเป็น)
จะเห็นได้ว่า มีการประกาศตัวแปรที่ชื่อว่า app ซึ่งเป็น express object และเมื่อเราทำการนำ module ต่างๆ เช่น bodyParser, cookieParser ใส่ลงไป app แล้วส่วนต่อไปจะเป็นการใส่ router ที่ใช้ในการ Handling APIต่างๆที่สร้างขึ้นมา
โดย /routes/api.js ก็คือไฟล์หลักที่กำหนด path Restful API ที่ใช้ในระบบ NBLOGIC

api.js

ส่วนแรกจะเป็นส่วนของการ Import Module เข้ามาใช้งานภายในไฟล์นี้
var express = require('express');
var router = express.Router();
const request = require('request')
const {PythonShell} =  require('python-shell');
var cors = require('cors');
var mysql = require('mysql');
const nblogic_node = '/home/ec2-user/nblogic/routes/nblogic_node.py';
var _ = require('lodash');
require('dotenv').config()

ส่วนต่อไปจะเป็นส่วนที่กำหนด option ของ MySQL ที่เราจะทำการสร้าง Connection แบบ Pool ไว้

var connection = mysql.createPool({
  localAddress: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASS,
  database: "nblogic",
  port: 3306,
 socketPath: '/var/lib/mysql/mysql.sock',
 multipleStatements: true
});

ต่อไปจะเป็นตัวอย่างของ ส่วนการทำงาน (Function) ที่ขอข้อมูลของนักศึกษา (Student)

const sqlQuery = (query, data) => {
 return new Promise((resolve, reject) => {
  data?connection.query(query, data, (error, result) => {
   queryHandle(resolve, reject, result, error)
  }):connection.query(query, (error, result) => {
   queryHandle(resolve, reject, result, error)
  })
 })
}
const getUserData = (username) => {
 return sqlQuery(`SELECT * FROM student WHERE student.Student_ID = ${username}`)
}
const getUserAttemps = (username) => {
 return sqlQuery(`SELECT attemps.Course_id, Name, Year, Semester, Grade FROM attemps INNER JOIN course 
  ON course.Course_id = attemps.Course_id WHERE attemps.Student_ID = ${username}
  `)
}
router.get('/db/user/:userId', cors(), (req, res, next) => {
 var userId = req.params.userId;
 getUserData(userId).catch(error => {
  res.status(500).send(error)
 }).then(data_result => {
  return data_result
 }).then(data_result => {
  getUserAttemps(userId).catch(error => {
   res.status(500).send(error)
  }).then(attemp_result => {
   res.send({"User_Bio": data_result[0], "Attemps": attemp_result});
  })
 })
});

ก่อนที่จะพูดถึงในส่วนของ function ของการ login ต่อไปจะกล่าวการเขียนสคริปต์ Python
ซึ่งเป็นการเขียนสคริปต์ เพื่อเรียกใช้ module NBLOGIC ของ Python เพื่อที่จะใช้งานในส่วนการเข้าสู่ระบบของ KLOGIC ซึ่งจะได้มาซึ่งข้อมูลของนักศึกษาเกือบทั้งหมด

import sys
import json
import nblogic

nb = nblogic.KLOGIC(apiMode=True)

args = sys.argv
username = args[1]
password = args[2]
mode = args[3]

if(nb.authentication(username, password)):
    if mode == "authen":
        nb.get_bio()
        nb.get_information()
        nb.get_program_course()
        print(json.dumps(json.loads(nb.json(language="EN"))))
    sys.stdout.flush()

หลังจากได้รับข้อมูลจาก Python(PythonShell) ผ่าน sys.stdout.flush() แล้วก็จะถูกนำไปใช้ในไฟล์ api.js ต่อไป ดังโค้ด

router.post('/klogic', cors(), function(req, res, next) {
 let username = req.body.username;
 let password = req.body.password;
 let api_mode = req.body.api_mode;
 let options = {
  args: [username, password, "authen"],
  pythonPath: '/usr/bin/python3.7',
 }
 console.log(req.body)
 if (username && password) {
  PythonShell.run(nblogic_node, options, function (err, results) {
   if (err) {
    res.status(500).send(err);
   }
   console.log('nblogic_node finished.');
   console.log(results)
   results_json = JSON.parse(results);
   if (results_json !== null) {
    api_mode ? res.send(results_json) : res.render('profile', { title: "NBLOGIC", data: results_json['User_Bio'] });
    let user_bio = results_json['User_Bio']
    var full_course = results_json['User_Summary'];
    sqlQuery("INSERT INTO student SET ?", user_bio).then(result => {
     console.log("INSERT STUDENT SUCCESS");
     return sqlQuery(`UPDATE student SET GPAX = ${user_bio.GPAX} WHERE Student_ID = "${user_bio.Student_ID}"`)
    }).catch(errorHandle).then(result => {
     console.log("UPDATE GPAX SUCCESS");
     return sqlQuery("INSERT IGNORE INTO course (Name, Course_id, Credit_points) VALUES ?", [full_course.all_course.map(course =>
      [course.Name, course.Course_id, course.Credit_points])])
    }).catch(errorHandle).then(result => {
     console.log("INSERT COURSE SUCCESS")
     return sqlQuery("INSERT IGNORE INTO attemps (Student_id, Course_id, Year, Semester, Grade) VALUES ?", [full_course.attemp.map(attemp =>
      [attemp.Student_id, attemp.Course_id, attemp.Year, attemp.Semester, attemp.Grade])])
    }).catch(errorHandle).then(result => {
     console.log("INSERT Attemps SUCCESS")
     return sqlQuery("INSERT IGNORE INTO contains (Program_id, Course_id) VALUES ?", [full_course.all_course.map(course_ =>
      [full_course.User_info.Program_ID, course_.Course_id])])
    }).catch(errorHandle).then(result => {
     console.log("INSERT Contains SUCCESS")
     results_json = null;
    }).catch(errorHandle)
   }
   else {
    res.status(500).send('Something broke!')
   }
  });
 } else {
  res.status(401).send("Unauthorize!")
 }
});

References


ไม่มีความคิดเห็น:

แสดงความคิดเห็น