UNPKG

@navarrotech/servefunctions

Version:

If you're used to writing serverless functions in individual files, but need to write them on an express.js app, this package makes that easy.

122 lines (98 loc) 3.3 kB
const path = require("path") const fs = require("fs") const fileEndingRegex = new RegExp(/(t|j)s$/) module.exports = function (app, options={}) { let { path: directoryPath='./functions', defaultMethod='post', middleware=[], autoTryCatch=false, auto500Message="Something went wrong, please try again later.", verbose=false } = (options || {}) defaultMethod = defaultMethod.toLowerCase(); // Statistics let directoriesCount = 0, filesCount = 0; function scanDirectory(pathname, history = []) { fs .readdirSync(pathname) .forEach((fileName) => { let filePath = path.join(pathname, fileName) let file = fs.lstatSync(filePath) // If it's a directory, keep scanning! if (file.isDirectory()) { directoriesCount += 1; return scanDirectory(filePath, [...history, fileName]) } filesCount += 1; // If it's a file, initialize it! let url = "/" + path.join(history.join("/"), fileName), fn = require(path.join(filePath)) if(!fn || typeof fn !== 'function') return console.warn(`Unable to init function as the file's return method is not a function:\n${url}`) let preMiddlewares = [], postMiddlewares = [], method = null middleware .filter(mid => mid?.match.test(url)) .forEach(mid => { if(!method && mid?.method) method = mid.method?.toLowerCase() if(mid?.pre && mid.pre.length) preMiddlewares.push(...mid.pre) if(mid?.post && mid.post.length) postMiddlewares.push(...mid.post) }) // Url options if (fileEndingRegex.test(url)) { url = url.slice(0, -3) fileName = url.slice(0, -3) } if (fileName === 'index') { url = url.slice(0, -5) } let proxy = null; if(autoTryCatch){ proxy = function(req, res, ...props) { try { fn(req, res, props) } catch(exception) { console.error(exception) if(!res.headersSent) { if(auto500Message){ res.status(500).send(auto500Message) } else { res.sendStatus(500) } } } } } app[method || defaultMethod](url, ...preMiddlewares, (proxy || fn), ...postMiddlewares) }) } scanDirectory( resolvePath(directoryPath), [] ) if(verbose){ if(!!directoriesCount) console.log(`Scanned ${directoriesCount} sub-directories and created ${filesCount} routes!`) else if(!!filesCount) console.log(`Created ${filesCount} routes!`) } } function resolvePath(directoryPath){ // First try a relative import let startPath = path.resolve(directoryPath) // Then try an import from the project root if(!fs.existsSync(startPath)){ throw new Error(`Functions directory does not exist in: \n >> ${startPath}\n In ${directoryPath}\n`) } // Must be a directory let pathStats = fs.lstatSync(startPath) if(!pathStats.isDirectory()){ throw new Error(`Functions path is not a directory!`) } return startPath }