-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature/1309: API version separation in NodeJS backend (#1318)
* Total restructuring inside the /api dir: - v1 and v2 have their own dirs - I appended a .v2 to all logger definitions for API V2 controllers/services - I removed the obsolete endpoints from V2 - Added the new endpoints: PUT and DELETE /mapconfig/{name} instead of /mapconfig/create/{name} and /mapconfig/delete/{name}. This was already changed in the API spec so we will now conform to that - This is by no means complete (at least I think there's room for improvement). See this as a proposal for future structure inside the Backend dir and please let me know what you think in #1309. * Next step in the transision: clean up the Router a bit * Another step forward: - Separation of API requires either duplicating a lot of functionality (common to the API versions) or drawing a line somewhere and saying 'hey, this part of code should be shared between versions'. - That's what I'm attemptign to do here and opinions are welcome. - The 'line' is currently drawn at 'stuff that don't expose /api/vN endpoint should be shared'. So we share the error handler, logger and detailed logger middlewares. The proxy middlewares and perhaps even the static files exposer middleware will be placed inside each API's version. That will come in a future commit. * Prepared two product proxies for versioning. * Major changes in server.js to make room for versioning: - Added a key in .env, API_VERSIONS. It can contain a comma-separated list of integers that corespond to API versions. By default any empty value or no value at all means that all API versions are enabled. - Added a apiVersions constant both in server.js and as an Express app variable, so we can do app.get(apiVersions) anywhere and get the array. Nice. - Moved two product proxies (FME Server and Sokigo FB) to helper methods. Inside of them, we iterate and import required proxies dynamically. - Another iteration takes place to set up the OpenAPI Validator middleware and expose the specification, depending on which versions are required. Also nice. * Disabled http-middleware-proxy's internal logging: - There were issues with it: seemingly the last middleware to be setup got all logging messages to it, which is unintended. - The logging we setup ourselves in the middlewares is fine though. Since we take care of both success and error and log then correctly, there was no use for HPM's internal logging. * Small cleanups * Generic proxy versioning added. Also major improvements to API version check. - The generic proxy is not really versioned as it merely exposes some endpoints using HTTP Proxy Middleware. But we do expose proxies for each of the enabled versions of API to keep it consistent with previous Hajk versions. - The check added at startup ensure that we only attempt to initialize valid API versions. Those are, for now, kept in const ALLOWED_API_VERSIONS but could be moved further on. * Version bumped logger * Discovered that the Router imports all API versions - must be fixed prior release. * Added coherent initialization messages to Services in V2 * Added version info to V1 middlewares, for consistency. * The Static Exposer is now versioned too: - The static routes are still exposed outside the /api/vN, but the code used is dynamically imported. - Admin can specify a certain version of active API versions to use. Default value is the highest (latest) active API version. * Routes are created only for the active API versions, takes care of the bug discovered in 59b7915.
- Loading branch information
Showing
56 changed files
with
2,849 additions
and
158 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
.../server/api/middlewares/restrict.admin.js → ...ver/apis/v1/middlewares/restrict.admin.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...server/api/middlewares/restrict.static.js → ...er/apis/v1/middlewares/restrict.static.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import * as express from "express"; | ||
|
||
import configRouter from "./controllers/config/router"; | ||
import mapconfigRouter from "./controllers/mapconfig/router"; | ||
import settingsRouter from "./controllers/settings/router"; | ||
import informativeRouter from "./controllers/informative/router"; | ||
import adRouter from "./controllers/ad/router"; | ||
|
||
export default express | ||
.Router() | ||
.use("/config", configRouter) | ||
.use("/informative", informativeRouter) | ||
.use("/mapconfig", mapconfigRouter) | ||
.use("/settings", settingsRouter) | ||
.use("/ad", adRouter); |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import ActiveDirectoryService from "../../services/activedirectory.service"; | ||
import handleStandardResponse from "../../utils/handleStandardResponse"; | ||
import log4js from "log4js"; | ||
|
||
// Create a logger for admin events, those will be saved in a separate log file. | ||
const ael = log4js.getLogger("adminEvent.v2"); | ||
|
||
export class Controller { | ||
availableADGroups(req, res) { | ||
ActiveDirectoryService.getAvailableADGroups().then((data) => | ||
handleStandardResponse(res, data) | ||
); | ||
} | ||
|
||
findCommonADGroupsForUsers(req, res) { | ||
ActiveDirectoryService.findCommonADGroupsForUsers(req.query.users).then( | ||
(data) => handleStandardResponse(res, data) | ||
); | ||
} | ||
|
||
getStore(req, res) { | ||
// Extract the store name from request's path | ||
const store = req.route.path.substring(1); | ||
ActiveDirectoryService.getStore(store).then((data) => { | ||
handleStandardResponse(res, data); | ||
// If data doesn't contain the error property, we're good - print event to admin log | ||
!data.error && | ||
ael.info( | ||
`${res.locals.authUser} viewed contents of AD store "${store}"` | ||
); | ||
}); | ||
} | ||
|
||
flushStores(req, res) { | ||
ActiveDirectoryService.flushStores().then((data) => { | ||
handleStandardResponse(res, data); | ||
// If data doesn't contain the error property, we're good - print event to admin log | ||
!data.error && ael.info(`${res.locals.authUser} flushed all AD stores`); | ||
}); | ||
} | ||
} | ||
|
||
export default new Controller(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import * as express from "express"; | ||
import controller from "./controller"; | ||
import restrictAdmin from "../../middlewares/restrict.admin"; | ||
|
||
export default express | ||
.Router() | ||
.use(restrictAdmin) // We will not allow any of the following routes unless user is admin | ||
.get("/availableadgroups", controller.availableADGroups) | ||
.get("/findcommonadgroupsforusers", controller.findCommonADGroupsForUsers) | ||
.get("/users", controller.getStore) | ||
.get("/groups", controller.getStore) | ||
.get("/groupsPerUser", controller.getStore) | ||
.put("/flushStores", controller.flushStores); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
62 changes: 62 additions & 0 deletions
62
new-backend/server/apis/v2/controllers/informative/controller.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import InformativeService from "../../services/informative.service"; | ||
import log4js from "log4js"; | ||
|
||
// Create a logger for admin events, those will be saved in a separate log file. | ||
const ael = log4js.getLogger("adminEvent.v2"); | ||
|
||
export class Controller { | ||
create(req, res) { | ||
const { documentName, mapName } = JSON.parse(req.body); | ||
InformativeService.create(documentName, mapName).then((r) => { | ||
// FIXME: The buggy admin expects 200 and this string on success, | ||
// but I think that we'd do better with a meaningful JSON response. | ||
if (r && !r.error) { | ||
res.status(200).send("Document created"); | ||
ael.info( | ||
`${res.locals.authUser} created a new document, ${documentName}.json, and connected it to map ${mapName}.json` | ||
); | ||
} else res.status(500).send(r.error.message); | ||
}); | ||
} | ||
|
||
getByName(req, res) { | ||
InformativeService.getByName(req.params.name).then((r) => { | ||
if (r && !r.error) res.json(r); | ||
else { | ||
res | ||
.status(404) | ||
.send(`Document "${req.params.name}" could not be found`); | ||
} | ||
}); | ||
} | ||
|
||
saveByName(req, res) { | ||
InformativeService.saveByName(req.params.name, req.body).then((r) => { | ||
if (r && !r.error) { | ||
res.status(200).send("File saved"); | ||
ael.info( | ||
`${res.locals.authUser} saved document ${req.params.name}.json` | ||
); | ||
} else res.status(500).send(r.error.message); | ||
}); | ||
} | ||
|
||
deleteByName(req, res) { | ||
InformativeService.deleteByName(req.params.name).then((r) => { | ||
if (r && !r.error) { | ||
res.status(200).send("File saved"); | ||
ael.info( | ||
`${res.locals.authUser} deleted document ${req.params.name}.json` | ||
); | ||
} else res.status(500).send(r.error.message); | ||
}); | ||
} | ||
|
||
list(req, res) { | ||
InformativeService.getAvailableDocuments().then((r) => { | ||
if (r && !r.error) res.json(r); | ||
else res.status(500).send(r.error.message); | ||
}); | ||
} | ||
} | ||
export default new Controller(); |
13 changes: 13 additions & 0 deletions
13
new-backend/server/apis/v2/controllers/informative/router.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import * as express from "express"; | ||
import controller from "./controller"; | ||
import restrictAdmin from "../../middlewares/restrict.admin"; | ||
|
||
export default express | ||
.Router() | ||
.get("/load/:name", controller.getByName) | ||
.use(restrictAdmin) // All routes that follow are admin-only! | ||
.put("/create", controller.create) // PUT is correct here, as this operation is idempotent | ||
.delete("/delete/:name", controller.deleteByName) | ||
.get("/list", controller.list) | ||
.get("/list/:name", controller.list) // FIXME: For now, the name paramter is ignored - should list only documents connected to specified map | ||
.put("/save/:name", controller.saveByName); // PUT is correct here, as this operation is idempotent |
Oops, something went wrong.