Fixed handling of nested paths and custom routes

This commit is contained in:
Kawanaao 2023-12-06 00:11:05 +02:00
parent 90a8766b15
commit b29ab1fccb
No known key found for this signature in database
GPG key ID: 5B7A8DDCE861E7DC
2 changed files with 60 additions and 22 deletions

View file

@ -1,6 +1,7 @@
import { Request, Response } from "express"
import { resolve } from "path"
import { readFileSync } from "fs"
import { stringify } from "querystring"
import jsonServer from "json-server"
import traverse from "traverse"
@ -10,16 +11,10 @@ const definedDB: Record<string, any> = JSON.parse(readFileSync(resolve(__dirname
encoding: "utf8"
}))
const autoDB = traverse(definedDB)
.paths()
.map(pathArray => ({
path: pathArray.join("."),
data: pathArray.reduce((db, pathSegment) => db[pathSegment], definedDB)
}))
.map(dbEntry => (dbEntry.data = isObject(dbEntry.data) ? dbEntry.data : ["$return", dbEntry.data], dbEntry))
.reduce((acc, dbEntry) => (acc[dbEntry.path] = dbEntry.data, acc), {} as Record<string, any>)
const db = Object.assign({}, autoDB, definedDB)
const dbPaths = Object.keys(db)
const autoDB = genDB(definedDB)
const dbPaths = Object.keys(autoDB)
console.log(dbPaths)
// TODO: Reference types do not work at the ["$return", data] level
// A possible solution is to replace filter with map and custom behavior for get, post and put
@ -37,22 +32,15 @@ const autoRoutes = dbPaths
}))
.reduce((acc, bind) => (acc[bind.origin] = bind.destination, acc), {} as Record<string, string>)
const routes = Object.assign({}, autoRoutes, definedRoutes)
const proxyServer = jsonServer.create()
const middlewares = jsonServer.defaults()
const rewriter = jsonServer.rewriter(routes)
const router = jsonServer.router(db, {
const router = jsonServer.router(autoDB, {
foreignKeySuffix: "Id"
})
// @ts-ignore
router.render = (req: Request, res: Response) => {
const reqPath = req.path.replace("/", "")
const matchedPath = dbPaths
.map(path => path.replace(/\./g, "/"))
.find(path => path !== reqPath && reqPath.startsWith(path))
console.log(matchedPath)
if (typeof res.locals.data["_comment"] === "string" && res.locals.data["_comment"].toLowerCase().includes("todo"))
return res.sendStatus(404)
else if (Array.isArray(res.locals.data.list))
@ -79,9 +67,58 @@ proxyServer.use(jsonServer.bodyParser)
proxyServer.use(middlewares)
proxyServer.use("/api", rewriter)
proxyServer.use("/api", (req, res, next) => {
const query = stringify(req.query as Record<string, any>)
const dbKey = req.path
.replace("/", "")
.replace(/\//g, ".")
if (autoDB[dbKey])
req.url = `/${dbKey}${query ? "?" : ""}${query}`
next()
})
proxyServer.use("/api", router)
proxyServer.listen(PROXY_PORT, () => console.info(`JSON proxy is running on ${PROXY_PORT} port`))
function isObject(value: unknown) {
type JSONValue = string | number | boolean | JSONObject | JSONArray
interface JSONObject extends Record<string, JSONValue> { }
interface JSONArray extends Array<JSONValue> { }
function genDB(initialDB: JSONObject, skipRoot: boolean = true): Record<string, JSONValue> {
return traverse(initialDB)
.reduce(function (acc: Record<string, any>, node) {
if (skipRoot && this.isRoot)
return acc
const currentPath = this.path.join(".")
acc[currentPath] = isObject(node) ? node : ["$return", node]
if (Array.isArray(node)) {
node
.filter(isObject)
.map(childNode => [
Object.values(childNode),
genDB(childNode, false)
] as const)
.forEach(([values, childNodeDB]) =>
values
.filter(value => !!value && typeof value === "string" && !value.includes("."))
.forEach(value => Object.keys(childNodeDB).forEach(childNodePath =>
acc[`${currentPath}.${value}${childNodePath && "." || ""
}${childNodePath}`.replace(/\//g, ".")] = childNodeDB[childNodePath]
))
)
}
return acc
}, {})
}
function isObject(value: unknown): value is Record<string, any> {
return typeof value === 'object' && value !== null
}
}
// Проитерировать ключи обьекта
// сделать из них путь к базовому обьекту

View file

@ -1,9 +1,10 @@
{
"/servapps/:container/logs": "/servapps/demo/logs",
"/volume/:name": "/volumes/Volumes?Volumes.Name=:name",
"/volume/:name": "/volumes/Volumes?Name=:name",
"/network/:name": "/networks?Name=:name",
"/servapps/:id/secure/:res": "/servapps/demo/secure",
"/servapps/:id/manage/:action": "/servapps/demo/manage",
"/servapps/:id/networks": "/servapps/:id?_embed=NetworkSettings.Networks",
"/servapps/:id/networks": "/test/:id/NetworkSettings",
"/test/:id": "/servapps?Id=:id",
"/servapps/:containerId/network/:networkId": "/servapps/:containerId/networks"
}