-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: modularize bootstrap tasks in index.js (#1527)
- Loading branch information
Showing
10 changed files
with
467 additions
and
299 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
const path = require('node:path') | ||
const logger = require('../utils/logger') | ||
const packageJson = require("../package.json") | ||
|
||
function modulePathResolver( handlersPath, route, apiDoc ) { | ||
const pathKey = route.openApiRoute.substring(route.basePath.length) | ||
const schema = apiDoc.paths[pathKey][route.method.toLowerCase()] | ||
const controller = schema.tags[0] | ||
const method = schema['operationId'] | ||
const modulePath = path.join(handlersPath, controller) | ||
const handler = require(modulePath) | ||
if (handler[method] === undefined) { | ||
throw new Error( | ||
`Could not find a [${method}] function in ${modulePath} when trying to route [${route.method} ${route.expressRoute}].`, | ||
) | ||
} | ||
return handler[method] | ||
} | ||
|
||
function buildResponseValidationConfig(willValidateResponse) { | ||
if (willValidateResponse){ | ||
return { | ||
onError: (error, body, req) => { | ||
logger.writeError('rest', 'responseValidation', { | ||
error, | ||
request: logger.serializeRequest(req), | ||
body | ||
}) | ||
} | ||
} | ||
} | ||
else { | ||
return false | ||
} | ||
} | ||
|
||
function logAppConfig(config) { | ||
logger.writeInfo('bootstrapUtils', 'starting bootstrap', { | ||
version: packageJson.version, | ||
env: logger.serializeEnvironment(), | ||
dirname: __dirname, | ||
cwd: process.cwd() | ||
}) | ||
logger.writeInfo('bootstrapUtils', 'configuration', config) | ||
|
||
} | ||
|
||
module.exports = { | ||
modulePathResolver, | ||
buildResponseValidationConfig, | ||
logAppConfig | ||
} |
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,80 @@ | ||
const express = require('express') | ||
const path = require('path') | ||
const writer = require('../utils/writer') | ||
const logger = require('../utils/logger') | ||
const config = require('../utils/config') | ||
|
||
function serveClient(app) { | ||
|
||
if (config.client.disabled) { | ||
logger.writeDebug('serveClient', 'client', {message: 'client disabled'}) | ||
return | ||
} | ||
try { | ||
serveClientEnv(app) | ||
serveStaticFiles(app) | ||
logger.writeDebug('serveClient', 'client', { message: 'succeeded setting up client' }) | ||
} | ||
catch (err) { | ||
logger.writeError('serveClient', 'client', {message: err.message, stack: err.stack}) | ||
} | ||
} | ||
|
||
function getClientEnv(){ | ||
const envJS = | ||
`const STIGMAN = { | ||
Env: { | ||
version: "${config.version}", | ||
apiBase: "${config.client.apiBase}", | ||
displayAppManagers: ${config.client.displayAppManagers}, | ||
welcome: { | ||
image: "${config.client.welcome.image}", | ||
title: "${config.client.welcome.title.replace(/"/g, '\\"')}", | ||
message: "${config.client.welcome.message.replace(/"/g, '\\"')}", | ||
link: "${config.client.welcome.link}" | ||
}, | ||
commit: { | ||
branch: "${config.commit.branch}", | ||
sha: "${config.commit.sha}", | ||
tag: "${config.commit.tag}", | ||
describe: "${config.commit.describe}" | ||
}, | ||
oauth: { | ||
authority: "${config.client.authority}", | ||
clientId: "${config.client.clientId}", | ||
refreshToken: { | ||
disabled: ${config.client.refreshToken.disabled} | ||
}, | ||
extraScopes: "${config.client.extraScopes ?? ''}", | ||
scopePrefix: "${config.client.scopePrefix ?? ''}" | ||
}, | ||
experimental: { | ||
appData: "${config.experimental.appData}" | ||
} | ||
} | ||
}` | ||
return envJS | ||
} | ||
|
||
function serveClientEnv(app){ | ||
const envJS = getClientEnv() | ||
app.get('/js/Env.js', function (req, res) { | ||
req.component = 'static' | ||
writer.writeWithContentType(res, { payload: envJS, contentType: "application/javascript" }) | ||
}) | ||
} | ||
|
||
function serveStaticFiles(app){ | ||
const staticPath = path.join(__dirname, "../", config.client.directory) | ||
logger.writeDebug('serveStaticFiles', 'client', {client_static: staticPath}) | ||
const expressStatic = express.static(staticPath) | ||
|
||
app.use('/', (req, res, next) => { | ||
req.component = 'static' | ||
expressStatic(req, res, next) | ||
}) | ||
} | ||
|
||
module.exports = { | ||
serveClient, | ||
} |
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,38 @@ | ||
const logger = require('../utils/logger') | ||
const auth = require('../utils/auth') | ||
const db = require('../service/utils') | ||
const { serializeError } = require('../utils/serializeError') | ||
|
||
let depStatus = { | ||
db: 'waiting', | ||
auth: 'waiting' | ||
} | ||
|
||
async function initializeDependencies() { | ||
try { | ||
await Promise.all([ | ||
auth.initializeAuth(setDepStatus), | ||
db.initializeDatabase(setDepStatus) | ||
]) | ||
} catch (e) { | ||
logger.writeError('dependencies', 'shutdown', {message:'Failed to setup dependencies', error: serializeError(e)}) | ||
process.exit(1) | ||
} | ||
} | ||
|
||
function setDepStatus(service, status) { | ||
if (depStatus.hasOwnProperty(service)) { | ||
depStatus[service] = status | ||
} else { | ||
throw new Error(`Service ${service} is not recognized in depStatus`) | ||
} | ||
} | ||
|
||
function getDepStatus() { | ||
return depStatus | ||
} | ||
|
||
module.exports = { | ||
getDepStatus, | ||
initializeDependencies | ||
} |
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 @@ | ||
|
||
const express = require('express') | ||
const path = require('path') | ||
const fs = require('fs') | ||
const logger = require('../utils/logger') | ||
const config = require('../utils/config') | ||
const swaggerUi = require('swagger-ui-express') | ||
const jsyaml = require('js-yaml') | ||
|
||
function serveDocs(app) { | ||
if (config.docs.disabled) { | ||
logger.writeDebug('serveDocs', 'client', {message: 'documentation disabled'}) | ||
return | ||
} | ||
try { | ||
app.use('/docs', express.static(path.join(__dirname, "../", config.docs.docsDirectory))) | ||
logger.writeDebug('serveDocs', 'client', {message: 'succeeded setting up documentation'}) | ||
} | ||
catch (err) { | ||
logger.writeError('serveDocs', 'client', {message: err.message, stack: err.stack}) | ||
} | ||
} | ||
|
||
function serveApiDocs(app) { | ||
|
||
if (config.swaggerUi.enabled) { | ||
const oasDoc = getOAS() | ||
configureSwaggerUI(app, oasDoc) | ||
} | ||
else | ||
{ | ||
logger.writeDebug('serveApiDocs', 'SwaggerUI', { message: 'Swagger UI is disabled in configuration' }) | ||
} | ||
} | ||
|
||
function getOAS(){ | ||
// Read and modify OpenAPI specification | ||
const apiSpecPath = path.join(__dirname, '../specification/stig-manager.yaml') | ||
let spec = fs.readFileSync(apiSpecPath, 'utf8') | ||
let oasDoc = jsyaml.load(spec) | ||
// Replace with config values | ||
oasDoc.info.version = config.version | ||
oasDoc.servers[0].url = config.swaggerUi.server | ||
oasDoc.components.securitySchemes.oauth.openIdConnectUrl = `${config.client.authority}/.well-known/openid-configuration` | ||
config.definition = oasDoc | ||
return oasDoc | ||
} | ||
|
||
function configureSwaggerUI(app, oasDoc){ | ||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(oasDoc, null, { | ||
oauth2RedirectUrl: config.swaggerUi.oauth2RedirectUrl, | ||
oauth: { | ||
usePkceWithAuthorizationCodeGrant: true | ||
} | ||
})) | ||
app.get(['/swagger.json','/openapi.json'], function(req, res) { | ||
res.json(oasDoc) | ||
}) | ||
logger.writeDebug('configureSwaggerUI', 'client', {message: 'succeeded setting up swagger-ui'}) | ||
} | ||
|
||
module.exports = { serveDocs, serveApiDocs } |
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,32 @@ | ||
const logger = require('../utils/logger') | ||
const smErrors = require('../utils/error') | ||
const { serializeError } = require('../utils/serializeError') | ||
const path = require('path') | ||
|
||
function configureErrorHandlers(app) { | ||
// express-openapi-validator does not expose top-level HttpError in their index.js. | ||
// We can get it from framework.types.js | ||
// CAUTION: We break here if express-openapi-validator changes this | ||
const eovPath = path.dirname(require.resolve('express-openapi-validator')) | ||
const eovErrors = require(path.join(eovPath, 'framework', 'types.js')) | ||
app.use((err, req, res, next) => { | ||
if (!(err instanceof smErrors.SmError) && !(err instanceof eovErrors.HttpError)) { | ||
logger.writeError('rest', 'error', { | ||
request: logger.serializeRequest(req), | ||
error: serializeError(err) | ||
}) | ||
} | ||
|
||
res.errorBody = { error: err.message, code: err.code, detail: err.detail} | ||
if (err.status === 500 || !(err.status)) res.errorBody.stack = err.stack | ||
if (!res._headerSent) { | ||
res.status(err.status || 500).header(err.headers).json(res.errorBody) | ||
} | ||
else { | ||
res.write(JSON.stringify(res.errorBody) + '\n') | ||
res.end() | ||
} | ||
}) | ||
} | ||
|
||
module.exports = configureErrorHandlers |
Oops, something went wrong.