Browse Source

Merge branch 'feature/api-error-handler' into develop

rigwild 1 year ago
parent
commit
d8980abf1d
8 changed files with 97 additions and 10 deletions
  1. 47 0
      api/functions.js
  2. 5 0
      api/index.js
  3. 29 0
      api/routes/getImage.js
  4. 2 0
      api/routes/index.js
  5. 5 8
      api/routes/listScenes.js
  6. 1 1
      config.js
  7. 1 1
      package.json
  8. 7 0
      yarn.lock

+ 47 - 0
api/functions.js

@@ -0,0 +1,47 @@
+'use strict'
+
+import _fs, { promises as fs } from 'fs'
+import boom from 'boom'
+import { apiConfig } from '../config'
+
+/**
+ * Call the error handler if a middleware function throw an error
+ *
+ * @param {Function} fn original middleware function of the route
+ * @returns {Function} the same middleware function of the route but error handled
+ */
+export const asyncMiddleware = fn => (req, res, next) => {
+  Promise.resolve(fn(req, res, next)).catch(err => {
+    // Check whether the error is a boom error
+    if (!err.isBoom) {
+      // The error was not recognized, send a 500 HTTP error
+      return next(boom.internal(err))
+    }
+    // It is a boom error, give it to express to handle it
+    next(err)
+  })
+}
+
+// Middleware to handle middleware errors
+export const errorHandler = (err, req, res, next) => {
+  const { output: { payload } } = err
+  console.error(`Error ${payload.statusCode} - ${payload.error}\n${payload.message}\n`)
+  return res.status(payload.statusCode).json(payload)
+}
+
+/**
+ * Get a list of all available scenes
+ *
+ * @returns {string[]} the available scenes
+ */
+export const getAvailableScenes = async () => {
+  try {
+    // Check if the images directory exists
+    await fs.access(apiConfig.imagesPath, _fs.constants.R_OK)
+  }
+  catch (err) {
+    // The images directory does not exist or is not accessible
+    throw boom.badRequest(`Can't access the "${apiConfig.imagesPath}" directory. Check it exists and you have read permission on it.`)
+  }
+  return fs.readdir(apiConfig.imagesPath)
+}

+ 5 - 0
api/index.js

@@ -3,6 +3,7 @@
 import express from 'express'
 import routes from './routes'
 
+import { errorHandler } from './functions'
 import { apiConfig } from '../config'
 
 const app = express()
@@ -11,4 +12,8 @@ app.listen(apiConfig.port, () => {
   console.log('The server was started on http://localhost:' + apiConfig.port)
 })
 
+// Load all the routes in the server
 app.use(apiConfig.routePrefix, routes)
+
+// Error handler (Middleware called when throwing in another middleware)
+app.use(errorHandler)

+ 29 - 0
api/routes/getImage.js

@@ -0,0 +1,29 @@
+'use strict'
+
+import express from 'express'
+import { promises } from 'fs'
+
+import { apiConfig } from '../../config'
+
+const fs = promises
+
+const router = express.Router()
+
+router.get('/', async (req, res) => {
+  const requiredParameters = ['sceneName', 'imageQuality']
+  const params = req.query
+
+  // Check if all required parameters were passed
+  if (!requiredParameters.every(parameter => Object.keys(params).includes(parameter))) {
+    // Some parameters are missing
+    res.statusCode = 400
+    res.json({ error: `Missing parameter(s). Required parameters : ${requiredParameters.join(', ')}.` })
+    return
+  }
+
+  const dirContent = await fs.readdir(apiConfig.imagesPath)
+  res.json(req.query)
+  res.json({ msg: 'Not ready yet' })
+})
+
+export default router

+ 2 - 0
api/routes/index.js

@@ -2,9 +2,11 @@
 
 import express from 'express'
 import listScenes from './listScenes'
+import getImage from './getImage'
 
 const router = express.Router()
 
 router.use('/listScenes', listScenes)
+router.use('/getImage', getImage)
 
 export default router

+ 5 - 8
api/routes/listScenes.js

@@ -1,17 +1,14 @@
 'use strict'
 
 import express from 'express'
-import { promises } from 'fs'
-
-import { apiConfig } from '../../config'
-
-const fs = promises
+import { asyncMiddleware, getAvailableScenes } from '../functions'
 
 const router = express.Router()
 
-router.get('/', async (req, res) => {
-  const dirContent = await fs.readdir(apiConfig.imagesPath)
+router.get('/', asyncMiddleware(async (req, res) => {
+  const dirContent = await getAvailableScenes()
+  console.log('triggered')
   res.json(dirContent)
-})
+}))
 
 export default router

+ 1 - 1
config.js

@@ -6,7 +6,7 @@ const PRODUCTION_MODE = process.env.NODE_ENV === 'production'
 
 const apiConfig = {
   routePrefix: '/api',
-  port: PRODUCTION_MODE ? 80 : 8080,
+  port: PRODUCTION_MODE ? 80 : 5000,
   imagesPath: path.resolve(__dirname, 'images')
 }
 

+ 1 - 1
package.json

@@ -6,12 +6,12 @@
     "api:start": "node -r esm api/index.js",
     "api:dev": "nodemon --exec npm run api:start",
     "api:lint": "eslint api/ --fix",
-
     "app:dev": "vue-cli-service serve",
     "app:build": "vue-cli-service build",
     "app:lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "boom": "^7.3.0",
     "core-js": "^2.6.5",
     "esm": "^3.2.22",
     "express": "^4.16.4",

+ 7 - 0
yarn.lock

@@ -1567,6 +1567,13 @@ boolbase@^1.0.0, boolbase@~1.0.0:
   resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
   integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
 
+boom@^7.3.0:
+  version "7.3.0"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-7.3.0.tgz#733a6d956d33b0b1999da3fe6c12996950d017b9"
+  integrity sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==
+  dependencies:
+    hoek "6.x.x"
+
 boxen@^1.2.1:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"