Skip to content

Commit

Permalink
done Part14-API-Error
Browse files Browse the repository at this point in the history
  • Loading branch information
andy6804tw committed Jan 10, 2018
1 parent a9bb41d commit 1969e6f
Show file tree
Hide file tree
Showing 8 changed files with 375 additions and 5 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@
- 使用者登入
- [Link 連結](https://github.com/andy6804tw/RESTful_API_start_kit/tree/Part13-User-login)
- [Tutorial 教學](/tutorials/Part13-User-login.md)
- API Error
- [Link 連結](https://github.com/andy6804tw/RESTful_API_start_kit/tree/Part14-API-Error)
- [Tutorial 教學](/tutorials/Part14-API-Error.md)
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dotenv": "^4.0.0",
"express": "^4.16.2",
"express-validation": "^1.0.2",
"http-status": "^1.0.1",
"joi": "^13.0.2",
"morgan": "^1.9.0",
"mysql": "^2.15.0"
Expand Down
31 changes: 31 additions & 0 deletions src/config/express.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import morgan from 'morgan';
import httpStatus from 'http-status';
import expressValidation from 'express-validation';
import APPError from '../server/helper/AppError';
import config from './config';
import index from '../server/routes/index.route';

Expand All @@ -22,4 +25,32 @@ app.get('/', (req, res) => {

app.use('/api', index);

// if error is not an instanceOf APIError, convert it.
app.use((err, req, res, next) => {console.log('1')
let errorMessage;
let errorCode;
let errorStatus;
// express validation error 所有傳入參數驗證錯誤
if (err instanceof expressValidation.ValidationError) {
if (err.errors[0].location === 'query' || err.errors[0].location === 'body') {
errorMessage = err.errors[0].messages;
errorCode = 400;
errorStatus = httpStatus.BAD_REQUEST;
}
const error = new APPError.APIError(errorMessage, errorStatus, true, errorCode);
return next(error);
}
return next(err);
});

// error handler, send stacktrace only during development 錯誤後最後才跑這邊
app.use((err, req, res, next) => {console.log('2')
res.status(err.status).json({
message: err.isPublic ? err.message : httpStatus[err.status],
code: err.code ? err.code : httpStatus[err.status],
stack: config.env === 'development' ? err.stack : {}
});
next();
});

export default app;
4 changes: 2 additions & 2 deletions src/server/controllers/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ const test = (req, res) => {
};

/* User POST 登入(Login) */
const userLogin = (req, res) => {
const userLogin = (req, res, next) => {
// 取得帳密
const insertValues = req.body;
userModule.selectUserLogin(insertValues).then((result) => {
res.send(result); // 成功回傳result結果
}).catch((err) => { return res.send(err); }); // 失敗回傳錯誤訊息
}).catch((error) => { next(error); }); // 失敗回傳錯誤訊息
};


Expand Down
92 changes: 92 additions & 0 deletions src/server/helper/AppError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import httpStatus from 'http-status';

/**
* @extends Error
*/
class ExtendableError extends Error {
constructor(message, status, isPublic, code) {
super(message);
this.message = message;
this.name = this.constructor.name;
this.status = status;
this.isPublic = isPublic;
this.code = code;
this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
Error.captureStackTrace(this, this.constructor.name);
}
}

/**
* Class representing an API error.
* @extends ExtendableError
*/
class APIError extends ExtendableError {
/**
* Creates an API error.
* @param {string} message - Error message.
* @param {number} status - HTTP status code of error.
* @param {boolean} isPublic - Whether the message should be visible to user or not.
*/
constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false, code) {
super(message, status, isPublic, code);
this.name = 'APIError';
}
}

/**
* Class representing an MySQL error.
* @extends ExtendableError
*/
class MySQLError extends ExtendableError {
/**
* Creates an API error.
* @param {string} message - Error message.
* @param {number} status - HTTP status code of error.
* @param {boolean} isPublic - Whether the message should be visible to user or not.
*/
constructor(message = 'Backend Error', status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = true, code = 500) {
super(message, status, isPublic, code);
this.name = 'MySQLError';
}
}

/**
* 信箱尚未註冊 Error
* @extends ExtendableError
*/
class LoginError1 extends ExtendableError {
/**
* Creates an API error.
* @param {string} message - Error message.
* @param {number} status - HTTP status code of error.
* @param {boolean} isPublic - Whether the message should be visible to user or not.
*/
constructor(message = '信箱尚未註冊!', status = httpStatus.UNAUTHORIZED, isPublic = true, code = 401) {
super(message, status, isPublic, code);
this.name = 'LoginError';
}
}
/**
* 密碼錯誤 Error.
* @extends ExtendableError
*/
class LoginError2 extends ExtendableError {
/**
* Creates an API error.
* @param {string} message - Error message.
* @param {number} status - HTTP status code of error.
* @param {boolean} isPublic - Whether the message should be visible to user or not.
*/
constructor(message = '您輸入的密碼有誤!', status = httpStatus.UNAUTHORIZED, isPublic = true, code = 401) {
super(message, status, isPublic, code);
this.name = 'LoginError';
}
}


export default {
APIError,
MySQLError,
LoginError1,
LoginError2
};
5 changes: 3 additions & 2 deletions src/server/modules/user.module.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import mysql from 'mysql';
import bcrypt from 'bcrypt';
import config from '../../config/config';
import APPError from '../helper/AppError';

const connectionPool = mysql.createPool({
connectionLimit: 10,
Expand Down Expand Up @@ -120,15 +121,15 @@ const selectUserLogin = (insertValues) => {
console.error('SQL error: ', error);
reject(error); // 寫入資料庫有問題時回傳錯誤
} else if (Object.keys(result).length === 0) {
resolve('信箱尚未註冊!');
reject(new APPError.LoginError1()); // 信箱尚未註冊
} else {
const dbHashPassword = result[0].user_password; // 資料庫加密後的密碼
const userPassword = insertValues.user_password; // 使用者登入輸入的密碼
bcrypt.compare(userPassword, dbHashPassword).then((res) => { // 使用bcrypt做解密驗證
if (res) {
resolve('登入成功'); // 登入成功
} else {
resolve('您輸入的密碼有誤!'); // 登入失敗
reject(new APPError.LoginError2()); // 登入失敗 輸入的密碼有誤
}
});
}
Expand Down
Loading

0 comments on commit 1969e6f

Please sign in to comment.