-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcreate-route-handler.js
More file actions
151 lines (133 loc) · 5.34 KB
/
create-route-handler.js
File metadata and controls
151 lines (133 loc) · 5.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const logErrors = require('./log-errors')
const express = require("express");
const filenameMatching = require('./lib/filename-matching')
const noop = require('./lib/noop')
/**
*
* @param {String} FILES_DIR The directory where the JSON files are stored
* @returns {RouteHandler}
*/
module.exports = function createRouteHandler(FILES_DIR) {
/**
* Express middleware function that finds and returns the desired file. If the
* file can't be found, it returns an error
* @typedef RouteHandler
* @type {function}
* @param {express.Request} req
* @param {express.Response} res
*/
return function routeHandler(req, res) {
/** The requested URL */
const url = req.url || ''
/** Lowercase method used in request */
const method = req.method.toLowerCase()
/** URL without query params */
const cleanUrl = url.replace(/(\?.*)/, '')
try {
/** The requested cleanURL */
let input
/**
* The folder part of the requested URL
* Given the requested url: `/path/to/`file
*/
let folder
/**
* The last part of the requested URL
* Given the requested url: /path/to/`file`
*/
let file
// Deconstruct the url into parts so we know where to find the file
// the user requested
try {
const [_input, _folder = '.', _file] = /(.+\/)?([\w-]+)\/?$/.exec(cleanUrl)
input = _input
folder = _folder
file = _file
} catch (error) {
if (cleanUrl === '/') {
folder = '.'
file = 'index'
}
}
/**
* All the files in the folder part of the requested url
*/
const allFilesInFolder = fs
.readdirSync(path.join(FILES_DIR, folder))
// If the file part of the requested url happens to be a folder on disk,
// we expect to find an index.[json|txt] file, potentially with verb
// versions as well. In that case, add these to the allFilesInFolder array
try {
const subfiles = fs.readdirSync(path.join(FILES_DIR, folder, file))
if (subfiles.length > 0) {
subfiles.forEach(subfile => allFilesInFolder.push(`${file}/${subfile}`))
}
} catch (err) {
noop()
}
/** Only files that match the file part of the requested URL or index. */
const filesInFolder = allFilesInFolder
.filter(filenameMatching(file))
.filter(filenameMatching(`${method}|${file}(\/index)*.[json|txt]`))
const indexMethodFileJSON = filesInFolder.find(filenameMatching(`${file}/index.${method}.json`))
const indexMethodFileText = filesInFolder.find(filenameMatching(`${file}/index.${method}.txt`))
const indexFileJSON = filesInFolder.find(filenameMatching(`${file}/index.json`))
const indexFileText = filesInFolder.find(filenameMatching(`${file}/index.txt`))
const methodFileJSON = filesInFolder.find(filenameMatching(`.${method}.json`))
const methodFileText = filesInFolder.find(filenameMatching(`.${method}.txt`))
const fileJSON = filesInFolder.find(filenameMatching(`${file}.json`))
const fileText = filesInFolder.find(filenameMatching(`${file}.txt`))
// Send the file when found.
if (indexMethodFileJSON) {
res.json(JSON.parse(fs.readFileSync(path.join(FILES_DIR, folder, indexMethodFileJSON))))
} else if (indexMethodFileText) {
res.send(fs.readFileSync(path.join(FILES_DIR, folder, indexMethodFileText)))
} else if (indexFileJSON) {
res.json(JSON.parse(fs.readFileSync(path.join(FILES_DIR, folder, indexFileJSON))))
} else if (indexFileText) {
res.send(fs.readFileSync(path.join(FILES_DIR, folder, indexFileText)))
} else if (methodFileJSON) {
res.json(JSON.parse(fs.readFileSync(path.join(FILES_DIR, folder, methodFileJSON))))
} else if (methodFileText) {
res.send(fs.readFileSync(path.join(FILES_DIR, folder, methodFileText)))
} else if (fileJSON) {
res.json(JSON.parse(fs.readFileSync(path.join(FILES_DIR, folder, fileJSON))))
} else if (fileText) {
res.send(fs.readFileSync(path.join(FILES_DIR, folder, fileText)))
// We could not find the file on disk based on the deconstructed url parts
} else {
logErrors(
`${chalk.yellow(`${input}.${method}.json`)} or ${chalk.yellow(`${input}.json`)} not found`,
404
)
res
.status(404)
.send({ error: `${input}.${method}.json or ${input}.json not found` })
}
} catch (err) {
// The else statement above was not reached for some reason. Still we get
// an `No such file` error. So send an 404
if (new RegExp('no such file').test(err.message)) {
logErrors(
`${chalk.yellow(`${cleanUrl}.${method}.json`)} or ${chalk.yellow(`${cleanUrl}.json`)} not found`,
404
)
res
.status(404)
.send({ error: `${cleanUrl}.${method}.json or ${cleanUrl}.json not found` })
// Something else went wrong entirely, probably something in the provided
// middleware. Send the error message along so the user can debug it by
// itself
} else {
logErrors(
err.message,
500
)
res.status(500).send({ error: err.message })
}
}
}
}