adapt-authoring-server 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/errors/errors.json +9 -0
- package/lib/ServerModule.js +1 -0
- package/lib/ServerUtils.js +64 -0
- package/package.json +1 -1
package/errors/errors.json
CHANGED
|
@@ -7,6 +7,15 @@
|
|
|
7
7
|
"description": "API endpoint does not exist",
|
|
8
8
|
"statusCode": 404
|
|
9
9
|
},
|
|
10
|
+
"METHOD_NOT_ALLOWED": {
|
|
11
|
+
"data": {
|
|
12
|
+
"endpoint": "The endpoint",
|
|
13
|
+
"method": "The HTTP method",
|
|
14
|
+
"allowedMethods": "The allowed HTTP methods"
|
|
15
|
+
},
|
|
16
|
+
"description": "HTTP method not allowed for this endpoint",
|
|
17
|
+
"statusCode": 405
|
|
18
|
+
},
|
|
10
19
|
"NO_NET_CONN": {
|
|
11
20
|
"data": {
|
|
12
21
|
"hostname": "The hostname we were trying to reach"
|
package/lib/ServerModule.js
CHANGED
|
@@ -66,6 +66,7 @@ class ServerModule extends AbstractModule {
|
|
|
66
66
|
this.api.init()
|
|
67
67
|
this.root.init()
|
|
68
68
|
// add not-found handlers
|
|
69
|
+
this.api.expressRouter.use(ServerUtils.methodNotAllowedHandler(this.api))
|
|
69
70
|
this.api.expressRouter.use(ServerUtils.apiNotFoundHandler.bind(this))
|
|
70
71
|
this.root.expressRouter.use(ServerUtils.rootNotFoundHandler.bind(this))
|
|
71
72
|
// add generic error handling
|
package/lib/ServerUtils.js
CHANGED
|
@@ -15,6 +15,45 @@ class ServerUtils {
|
|
|
15
15
|
next(App.instance.errors.ENDPOINT_NOT_FOUND.setData({ endpoint: req.originalUrl, method: req.method }))
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Middleware for handling 405 Method Not Allowed errors
|
|
20
|
+
* Checks if the requested path exists with a different HTTP method
|
|
21
|
+
* @param {Router} router The router to check routes against
|
|
22
|
+
* @return {Function} Middleware function
|
|
23
|
+
*/
|
|
24
|
+
static methodNotAllowedHandler (router) {
|
|
25
|
+
const routePatterns = []
|
|
26
|
+
const routeMap = ServerUtils.getAllRoutes(router)
|
|
27
|
+
|
|
28
|
+
for (const [path, methods] of routeMap.entries()) {
|
|
29
|
+
const pathPattern = path
|
|
30
|
+
.replace(/\/:([^/?]+)\?/g, '(?:/([^/]+))?')
|
|
31
|
+
.replace(/:([^/]+)/g, '([^/]+)')
|
|
32
|
+
const regex = new RegExp(`^${pathPattern}$`)
|
|
33
|
+
routePatterns.push({ regex, methods })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return (req, res, next) => {
|
|
37
|
+
const requestMethod = req.method.toUpperCase()
|
|
38
|
+
|
|
39
|
+
for (const { regex, methods } of routePatterns) {
|
|
40
|
+
if (regex.test(req.path)) {
|
|
41
|
+
if (!methods.has(requestMethod)) {
|
|
42
|
+
const allowedMethods = Array.from(methods).sort().join(', ')
|
|
43
|
+
return next(App.instance.errors.METHOD_NOT_ALLOWED.setData({
|
|
44
|
+
endpoint: req.originalUrl,
|
|
45
|
+
method: req.method,
|
|
46
|
+
allowedMethods
|
|
47
|
+
}))
|
|
48
|
+
}
|
|
49
|
+
return next()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
next()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
18
57
|
/**
|
|
19
58
|
* Generic error handling middleware for the API router
|
|
20
59
|
* @param {Error} error
|
|
@@ -45,6 +84,31 @@ class ServerUtils {
|
|
|
45
84
|
return (req, res) => res.json(topRouter.map)
|
|
46
85
|
}
|
|
47
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Collects all registered routes with their methods across the router hierarchy
|
|
89
|
+
* @param {Router} router The router to traverse
|
|
90
|
+
* @return {Map<string, Set<string>>} Map of route paths to sets of allowed methods
|
|
91
|
+
*/
|
|
92
|
+
static getAllRoutes (router) {
|
|
93
|
+
const routeMap = new Map()
|
|
94
|
+
|
|
95
|
+
router.flattenRouters().forEach(r => {
|
|
96
|
+
r.routes.forEach(route => {
|
|
97
|
+
const fullPath = `${r.path !== '/' ? r.path : ''}${route.route}`
|
|
98
|
+
|
|
99
|
+
if (!routeMap.has(fullPath)) {
|
|
100
|
+
routeMap.set(fullPath, new Set())
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Object.keys(route.handlers).forEach(method => {
|
|
104
|
+
routeMap.get(fullPath).add(method.toUpperCase())
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
return routeMap
|
|
110
|
+
}
|
|
111
|
+
|
|
48
112
|
/**
|
|
49
113
|
* Generates a map for a given router
|
|
50
114
|
* @param {Router} topRouter
|
package/package.json
CHANGED