From a2b5a02f6b7b05ee92590ebdcbb61c1a072f24e0 Mon Sep 17 00:00:00 2001 From: Divlo Date: Thu, 19 Mar 2020 22:59:06 +0100 Subject: [PATCH] backend: Error handling middleware --- backend/app.js | 15 ++++++++------ backend/assets/config/errors.js | 13 ++++-------- .../assets/functions/main/armstrongNumber.js | 10 +++++----- backend/assets/functions/main/calculateAge.js | 11 +++++----- .../assets/functions/main/convertCurrency.js | 14 ++++++------- .../assets/functions/main/convertDistance.js | 10 +++++----- .../main/convertRomanArabicNumbers.js | 20 +++++++++---------- .../functions/main/convertTemperature.js | 12 +++++------ backend/assets/functions/main/randomNumber.js | 10 +++++----- .../assets/functions/main/weatherRequest.js | 8 ++++---- backend/assets/utils/errorHandling.js | 7 +++++++ backend/assets/utils/sendResponse.js | 11 ---------- backend/controllers/functions.js | 8 ++++---- 13 files changed, 71 insertions(+), 78 deletions(-) create mode 100644 backend/assets/utils/errorHandling.js delete mode 100644 backend/assets/utils/sendResponse.js diff --git a/backend/app.js b/backend/app.js index 385675a..17e4889 100644 --- a/backend/app.js +++ b/backend/app.js @@ -6,10 +6,9 @@ const cors = require('cors'); const morgan = require('morgan'); /* Files Imports & Variables */ -const { PORT } = require('./assets/config/config'); -const { serverError } = require('./assets/config/errors'); -const sendResponse = require('./assets/utils/sendResponse'); -const app = express(); +const { PORT } = require('./assets/config/config'); +const errorHandling = require('./assets/utils/errorHandling'); +const app = express(); /* Middlewares */ app.use(helmet()); @@ -21,8 +20,12 @@ app.use(express.json()); app.use('/functions', require('./routes/functions')); /* Errors Handling */ -app.use((_req, res, _next) => sendResponse(res, { result: "La route n'existe pas!", httpStatus: 404 })); // 404 -app.use((error, _req, res, _next) => { console.log(error); return sendResponse(res, serverError); }); // 500 +app.use((_req, _res, next) => errorHandling(next, { statusCode: 404, message: "La route n'existe pas!" })); // 404 +app.use((error, _req, res, _next) => { + console.log(error); + const { statusCode, message } = error; + return res.status(statusCode || 500).json({ message }); +}); /* Server */ app.listen(PORT, () => console.log('\x1b[36m%s\x1b[0m', `Started on port ${PORT}.`)); \ No newline at end of file diff --git a/backend/assets/config/errors.js b/backend/assets/config/errors.js index f7f7500..08f6f51 100644 --- a/backend/assets/config/errors.js +++ b/backend/assets/config/errors.js @@ -1,17 +1,12 @@ const errors = { generalError: { - result: "Vous n'avez pas rentré de valeur valide.", - httpStatus: 400 - }, - - serverError: { - result: "Le serveur n'a pas pu traiter votre requête.", - httpStatus: 500 + message: "Vous n'avez pas rentré de valeur valide.", + statusCode: 400 }, requiredFields: { - result: "Vous devez remplir tous les champs...", - httpStatus: 400 + message: "Vous devez remplir tous les champs...", + statusCode: 400 } }; diff --git a/backend/assets/functions/main/armstrongNumber.js b/backend/assets/functions/main/armstrongNumber.js index 6a97008..4a37d00 100644 --- a/backend/assets/functions/main/armstrongNumber.js +++ b/backend/assets/functions/main/armstrongNumber.js @@ -1,4 +1,4 @@ -const sendResponse = require('../../utils/sendResponse'); +const errorHandling = require('../../utils/errorHandling'); const { requiredFields } = require('../../config/errors'); const formatNumberResult = require('../secondary/formatNumberResult'); @@ -28,19 +28,19 @@ function armstrongNumber(number) { } /* OUTPUTS */ -exports.armstrongNumberOutput = (res, argsObject) => { +exports.armstrongNumberOutput = ({ res, next }, argsObject) => { let { number } = argsObject; // S'il n'y a pas les champs obligatoire if (!(number)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Si ce n'est pas un nombre number = parseInt(number); if (isNaN(number) || number <= 0) { - return sendResponse(res, { result: "Veuillez rentré un nombre valide.", httpStatus: 400 }); + return errorHandling(next, { message: "Veuillez rentré un nombre valide.", statusCode: 400 }); } - return sendResponse(res, { result: armstrongNumber(number) }, true); + return res.status(200).json(armstrongNumber(number)); } \ No newline at end of file diff --git a/backend/assets/functions/main/calculateAge.js b/backend/assets/functions/main/calculateAge.js index af1a729..2cb7293 100644 --- a/backend/assets/functions/main/calculateAge.js +++ b/backend/assets/functions/main/calculateAge.js @@ -1,4 +1,4 @@ -const sendResponse = require('../../utils/sendResponse'); +const errorHandling = require('../../utils/errorHandling'); const moment = require('moment'); const { requiredFields } = require('../../config/errors'); @@ -20,7 +20,7 @@ function calculateAge(currentDate, { birthDateDay, birthDateMonth, birthDateYear } /* OUTPUTS */ -exports.calculateAgeOutput = (res, argsObject) => { +exports.calculateAgeOutput = ({ res, next }, argsObject) => { let { birthDateDay, birthDateMonth, birthDateYear } = argsObject; birthDateDay = parseInt(birthDateDay); birthDateMonth = parseInt(birthDateMonth); @@ -28,16 +28,15 @@ exports.calculateAgeOutput = (res, argsObject) => { // S'il n'y a pas les champs obligatoire if (!(birthDateDay && birthDateMonth && birthDateYear)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Si ce n'est pas une date valide const currentDate = new Date(); const birthDate = new Date(birthDateYear, birthDateMonth - 1, birthDateDay); if (!(currentDate > birthDate)) { - return sendResponse(res, { result: "Veuillez rentré une date valide...", httpStatus: 400 }); + return errorHandling(next, { message: "Veuillez rentré une date valide...", statusCode: 400 }); } - const result = calculateAge(currentDate, { birthDateYear, birthDateMonth, birthDateDay }); - return sendResponse(res, { result }, true); + return res.status(200).json(calculateAge(currentDate, { birthDateYear, birthDateMonth, birthDateDay })); } \ No newline at end of file diff --git a/backend/assets/functions/main/convertCurrency.js b/backend/assets/functions/main/convertCurrency.js index e0eed74..73b92cb 100644 --- a/backend/assets/functions/main/convertCurrency.js +++ b/backend/assets/functions/main/convertCurrency.js @@ -1,20 +1,20 @@ -const axios = require('axios'); -const sendResponse = require('../../utils/sendResponse'); +const axios = require('axios'); +const errorHandling = require('../../utils/errorHandling'); const { requiredFields } = require('../../config/errors'); /* OUTPUTS */ -exports.convertCurrencyOutput = (res, argsObject) => { +exports.convertCurrencyOutput = ({ res, next }, argsObject) => { let { number, baseCurrency, finalCurrency } = argsObject; // S'il n'y a pas les champs obligatoire if (!(number && baseCurrency && finalCurrency)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Si ce n'est pas un nombre number = parseFloat(number); if (isNaN(number)) { - return sendResponse(res, { result: "Veuillez rentré un nombre valide.", httpStatus: 400 }); + return errorHandling(next, { message: "Veuillez rentré un nombre valide.", statusCode: 400 }); } axios.get(`https://api.exchangeratesapi.io/latest?base=${baseCurrency}`) @@ -25,7 +25,7 @@ exports.convertCurrencyOutput = (res, argsObject) => { const year = dateObject.getFullYear(); const day = ('0'+(dateObject.getDate())).slice(-2); const month = ('0'+(dateObject.getMonth()+1)).slice(-2); - return sendResponse(res, { result: { date: `${day}/${month}/${year}`, result } }, true); + return res.status(200).json({ date: `${day}/${month}/${year}`, result }); }) - .catch(() => sendResponse(res, { result: "La devise n'existe pas.", httpStatus: 404 })); + .catch(() => errorHandling(next, { message: "La devise n'existe pas.", statusCode: 404 })); } \ No newline at end of file diff --git a/backend/assets/functions/main/convertDistance.js b/backend/assets/functions/main/convertDistance.js index 3fa5e7a..0662944 100644 --- a/backend/assets/functions/main/convertDistance.js +++ b/backend/assets/functions/main/convertDistance.js @@ -1,4 +1,4 @@ -const sendResponse = require('../../utils/sendResponse'); +const errorHandling = require('../../utils/errorHandling'); const { requiredFields, generalError } = require('../../config/errors'); const correspondancesDistance = ["pm", null, null, "nm", null, null, "µm", null, null, "mm", "cm", "dm", "m", "dam", "hm", "km", null, null, "Mm", null, null, "Gm", null, null, "Tm"]; @@ -27,18 +27,18 @@ function convertDistance(firstValue, unitFirstValue, unitFinalValue) { } /* OUTPUTS */ -exports.convertDistanceOutput = (res, argsObject) => { +exports.convertDistanceOutput = ({ res, next }, argsObject) => { let { number, numberUnit, finalUnit } = argsObject; // S'il n'y a pas les champs obligatoire if (!(number && numberUnit && finalUnit)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Si ce n'est pas un nombre number = parseInt(number); if (isNaN(number)) { - return sendResponse(res, { result: "Veuillez rentré un nombre valide.", httpStatus: 400 }); + return errorHandling(next, { message: "Veuillez rentré un nombre valide.", statusCode: 400 }); } const result = convertDistance(number, numberUnit, finalUnit); @@ -46,5 +46,5 @@ exports.convertDistanceOutput = (res, argsObject) => { return sendResponse(res, generalError); } - return sendResponse(res, { result }, true); + return res.status(200).json(result); } \ No newline at end of file diff --git a/backend/assets/functions/main/convertRomanArabicNumbers.js b/backend/assets/functions/main/convertRomanArabicNumbers.js index 11fb787..afd52ac 100644 --- a/backend/assets/functions/main/convertRomanArabicNumbers.js +++ b/backend/assets/functions/main/convertRomanArabicNumbers.js @@ -1,4 +1,4 @@ -const sendResponse = require('../../utils/sendResponse'); +const errorHandling = require('../../utils/errorHandling'); const { requiredFields, generalError } = require('../../config/errors'); /* Variable pour convertRomanArabicNumbers */ @@ -67,12 +67,12 @@ function convertRomanToArabic(str) { } /* OUTPUTS */ -exports.convertRomanToArabicOutput = (res, argsObject) => { +exports.convertRomanToArabicOutput = ({ res, next }, argsObject) => { let { romanNumber } = argsObject; // S'il n'y a pas les champs obligatoire if (!(romanNumber)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Formate le paramètre @@ -80,30 +80,30 @@ exports.convertRomanToArabicOutput = (res, argsObject) => { romanNumber = romanNumber.toUpperCase(); } catch { - return sendResponse(res, generalError); + return errorHandling(next, generalError); } const result = convertRomanToArabic(romanNumber); if (result === 0) { - return sendResponse(res, generalError); + return errorHandling(next, generalError); } - return sendResponse(res, { result }, true); + return res.status(200).json({ result }); } -exports.convertArabicToRomanOutput = (res, argsObject) => { +exports.convertArabicToRomanOutput = ({ res, next }, argsObject) => { let { number } = argsObject; // S'il n'y a pas les champs obligatoire if (!(number)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Si ce n'est pas un nombre number = parseInt(number); if (isNaN(number)) { - return sendResponse(res, { result: "Veuillez rentré un nombre valide.", httpStatus: 400 }); + return errorHandling(next, { message: "Veuillez rentré un nombre valide.", statusCode: 400 }); } - return sendResponse(res, { result: convertArabicToRoman(number) }, true); + return res.status(200).json({ result: convertArabicToRoman(number) }); } \ No newline at end of file diff --git a/backend/assets/functions/main/convertTemperature.js b/backend/assets/functions/main/convertTemperature.js index fb6dfd1..8cf2339 100644 --- a/backend/assets/functions/main/convertTemperature.js +++ b/backend/assets/functions/main/convertTemperature.js @@ -1,4 +1,4 @@ -const sendResponse = require('../../utils/sendResponse'); +const errorHandling = require('../../utils/errorHandling'); const { requiredFields, generalError } = require('../../config/errors'); /** @@ -29,24 +29,24 @@ function convertTemperature(degree, unit) { } /* OUTPUTS */ -exports.convertTemperatureOutput = (res, argsObject) => { +exports.convertTemperatureOutput = ({ res, next }, argsObject) => { let { degree, unit } = argsObject; // S'il n'y a pas les champs obligatoire if (!(degree && unit)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Si ce n'est pas un nombre degree = parseInt(degree); if (isNaN(degree)) { - return sendResponse(res, { result: "Veuillez rentré un nombre valide.", httpStatus: 400 }); + return errorHandling(next, { message: "Veuillez rentré un nombre valide.", statusCode: 400 }); } const result = convertTemperature(degree, unit); if (!result) { - return sendResponse(res, generalError); + return errorHandling(next, generalError); } - return sendResponse(res, { result }, true); + return res.status(200).json({ result }); } \ No newline at end of file diff --git a/backend/assets/functions/main/randomNumber.js b/backend/assets/functions/main/randomNumber.js index d4c5b38..9d7563a 100644 --- a/backend/assets/functions/main/randomNumber.js +++ b/backend/assets/functions/main/randomNumber.js @@ -1,4 +1,4 @@ -const sendResponse = require('../../utils/sendResponse'); +const errorHandling = require('../../utils/errorHandling'); const { requiredFields } = require('../../config/errors'); /** @@ -13,20 +13,20 @@ function randomNumber(min, max) { } /* OUTPUTS */ -exports.randomNumberOutput = (res, argsObject) => { +exports.randomNumberOutput = ({ res, next }, argsObject) => { let { min, max } = argsObject; // S'il n'y a pas les champs obligatoire if (!(min && max)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Si ce ne sont pas des nombres min = parseInt(min); max = parseInt(max); if (isNaN(min) || isNaN(max)) { - return sendResponse(res, { result: "Les paramètres min et max doivent être des nombres...", httpStatus: 400 }); + return errorHandling(next, { message: "Les paramètres min et max doivent être des nombres...", statusCode: 400 }); } - return sendResponse(res, { result: randomNumber(min, max) }, true); + return res.status(200).json({ result: randomNumber(min, max) }); } \ No newline at end of file diff --git a/backend/assets/functions/main/weatherRequest.js b/backend/assets/functions/main/weatherRequest.js index cda020b..a5a0edc 100644 --- a/backend/assets/functions/main/weatherRequest.js +++ b/backend/assets/functions/main/weatherRequest.js @@ -1,6 +1,6 @@ const axios = require('axios'); const Queue = require('smart-request-balancer'); -const sendResponse = require('../../utils/sendResponse'); +const errorHandling = require('../../utils/errorHandling'); const { requiredFields } = require('../../config/errors'); const { WEATHER_API_KEY } = require('../../config/config'); @@ -25,13 +25,13 @@ exports.weatherRequestOutput = async (res, argsObject) => { // S'il n'y a pas les champs obligatoire if (!(cityName)) { - return sendResponse(res, requiredFields); + return errorHandling(next, requiredFields); } // Récupère les données météo grâce à l'API : openweathermap.org. (→ avec limite de 50 requêtes par minute) queue.request(() => { axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${cityName}&lang=fr&units=metric&appid=${WEATHER_API_KEY}`) - .then((response) => sendResponse(res, { result: response.data }, true)) - .catch(() => sendResponse(res, { result: "La ville n'existe pas (dans l'API de openweathermap.org).", httpStatus: 404 })); + .then((response) => res.status(200).json(response.data)) + .catch(() => errorHandling(next, { message: "La ville n'existe pas (dans l'API de openweathermap.org).", statusCode: 404 })); }, 'everyone', 'weatherRequest'); } \ No newline at end of file diff --git a/backend/assets/utils/errorHandling.js b/backend/assets/utils/errorHandling.js new file mode 100644 index 0000000..fde2917 --- /dev/null +++ b/backend/assets/utils/errorHandling.js @@ -0,0 +1,7 @@ +function errorHandling(next, { statusCode, message }) { + const error = new Error(message); + error.statusCode = statusCode; + next(error); +} + +module.exports = errorHandling; \ No newline at end of file diff --git a/backend/assets/utils/sendResponse.js b/backend/assets/utils/sendResponse.js deleted file mode 100644 index 26cfdcf..0000000 --- a/backend/assets/utils/sendResponse.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @description Envoie la réponse au client - * @param {Response} res Objet réponse d'une réponse http/express - * @param {Object} object { httpStatus, customProperties{Object}, result } - * @param {Boolean} isSuccess (false par defaut) - */ -function sendResponse(res, object, isSuccess = false) { - res.status(object.httpStatus || 200).json({ isSuccess, ...object.customProperties, result: object.result }); -} - -module.exports = sendResponse; \ No newline at end of file diff --git a/backend/controllers/functions.js b/backend/controllers/functions.js index 704679c..407a5e0 100644 --- a/backend/controllers/functions.js +++ b/backend/controllers/functions.js @@ -1,10 +1,10 @@ +const errorHandling = require('../assets/utils/errorHandling'); const functionToExecute = require('../assets/functions/functionObject'); -const sendResponse = require('../assets/utils/sendResponse'); -exports.executeFunctionName = (req, res, _next) => { +exports.executeFunctionName = (req, res, next) => { const functionOutput = functionToExecute(req.params.functionName); if (functionOutput !== undefined) { - return functionOutput(res, req.body); + return functionOutput({ res, next }, req.body); } - return sendResponse(res, { result: "La fonction n'existe pas.", httpStatus: 404 }); + return errorHandling(next, { message: "La fonction n'existe pas.", statusCode: 404 }); } \ No newline at end of file