Replace Application class w/ configureApplication
This commit is contained in:
parent
64f5f2f642
commit
8ca6107ce6
@ -1,155 +0,0 @@
|
|||||||
import * as middleware from '../middleware'
|
|
||||||
import * as routes from '../routes'
|
|
||||||
import * as rpc from '../rpc'
|
|
||||||
import * as services from '../services'
|
|
||||||
import * as team from '../team'
|
|
||||||
import * as user from '../user'
|
|
||||||
import cookieParser from 'cookie-parser'
|
|
||||||
import express from 'express'
|
|
||||||
import {keys} from 'ts-transformer-keys'
|
|
||||||
import {AsyncRouter, TransactionalRouter} from '../router'
|
|
||||||
import {IApplication} from './IApplication'
|
|
||||||
import {IConfig} from './IConfig'
|
|
||||||
import {IDatabase} from '../database/IDatabase'
|
|
||||||
import {ILogger} from '../logger/ILogger'
|
|
||||||
import {IRoutes, IContext} from '@rondo.dev/common'
|
|
||||||
import {IServices} from './IServices'
|
|
||||||
import {ITransactionManager} from '../database/ITransactionManager'
|
|
||||||
import {loggerFactory} from '../logger'
|
|
||||||
import {ILoggerFactory} from '@rondo.dev/logger'
|
|
||||||
import {json} from 'body-parser'
|
|
||||||
import {jsonrpc} from '@rondo.dev/jsonrpc'
|
|
||||||
|
|
||||||
export class Application implements IApplication {
|
|
||||||
readonly transactionManager: ITransactionManager
|
|
||||||
readonly server: express.Application
|
|
||||||
|
|
||||||
readonly services: IServices
|
|
||||||
readonly authenticator: middleware.Authenticator
|
|
||||||
|
|
||||||
readonly loggerFactory: ILoggerFactory = loggerFactory
|
|
||||||
|
|
||||||
constructor(readonly config: IConfig, readonly database: IDatabase) {
|
|
||||||
this.transactionManager = database.transactionManager
|
|
||||||
|
|
||||||
this.services = this.configureServices()
|
|
||||||
|
|
||||||
this.authenticator = new middleware.Authenticator(this.services.userService)
|
|
||||||
|
|
||||||
this.server = this.createServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configureServices(): IServices {
|
|
||||||
return {
|
|
||||||
userService: new services.UserService(this.database),
|
|
||||||
teamService: new team.TeamService(this.database),
|
|
||||||
userPermissions: new user.UserPermissions(this.database),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getApiLogger(): ILogger {
|
|
||||||
return this.loggerFactory.getLogger('api')
|
|
||||||
}
|
|
||||||
|
|
||||||
protected createServer() {
|
|
||||||
const server = express()
|
|
||||||
server.set('trust proxy', 1)
|
|
||||||
server.disable('x-powered-by')
|
|
||||||
|
|
||||||
const router = express.Router()
|
|
||||||
|
|
||||||
this.configureMiddleware(router)
|
|
||||||
this.configureRouter(router)
|
|
||||||
this.configureRPC(router)
|
|
||||||
this.configureApiErrorHandling(router)
|
|
||||||
this.configureFrontend(router)
|
|
||||||
|
|
||||||
server.use(this.config.app.context, router)
|
|
||||||
this.configureGlobalErrorHandling(server)
|
|
||||||
return server
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configureMiddleware(router: express.Router) {
|
|
||||||
const {transactionManager} = this
|
|
||||||
const apiLogger = this.getApiLogger()
|
|
||||||
|
|
||||||
router.use(new middleware.SessionMiddleware({
|
|
||||||
transactionManager,
|
|
||||||
baseUrl: this.config.app.baseUrl,
|
|
||||||
sessionName: this.config.app.session.name,
|
|
||||||
sessionSecret: this.config.app.session.secret,
|
|
||||||
}).handle)
|
|
||||||
router.use(new middleware.RequestLogger(apiLogger).handle)
|
|
||||||
router.use(json())
|
|
||||||
router.use(cookieParser(this.config.app.session.secret))
|
|
||||||
router.use(new middleware.CSRFMiddleware({
|
|
||||||
baseUrl: this.config.app.baseUrl,
|
|
||||||
cookieName: this.config.app.session.name + '_csrf',
|
|
||||||
}).handle)
|
|
||||||
router.use(new middleware.Transaction(this.database.namespace).handle)
|
|
||||||
|
|
||||||
router.use(this.authenticator.handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configureRouter(router: express.Router) {
|
|
||||||
// TODO use /api for LoginRoutes
|
|
||||||
router.use('/app', routes.application)
|
|
||||||
|
|
||||||
router.use('/api', new routes.LoginRoutes(
|
|
||||||
this.services.userService,
|
|
||||||
this.authenticator,
|
|
||||||
this.createTransactionalRouter(),
|
|
||||||
).handle)
|
|
||||||
router.use('/api', new routes.UserRoutes(
|
|
||||||
this.services.userService,
|
|
||||||
this.createTransactionalRouter(),
|
|
||||||
).handle)
|
|
||||||
|
|
||||||
router.use('/api', new team.TeamRoutes(
|
|
||||||
this.services.teamService,
|
|
||||||
this.services.userPermissions,
|
|
||||||
this.createTransactionalRouter(),
|
|
||||||
).handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getContext(req: express.Request): IContext {
|
|
||||||
return {user: req.user}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected jsonrpc() {
|
|
||||||
return jsonrpc(
|
|
||||||
req => this.getContext(req),
|
|
||||||
this.getApiLogger(),
|
|
||||||
(path, service, callback) => this
|
|
||||||
.database
|
|
||||||
.transactionManager
|
|
||||||
.doInNewTransaction(() => callback()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configureRPC(router: express.Router) {
|
|
||||||
// Override this method
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configureApiErrorHandling(router: express.Router) {
|
|
||||||
const apiLogger = this.getApiLogger()
|
|
||||||
router.use('/api', new middleware.ErrorApiHandler(apiLogger).handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configureFrontend(router: express.Router) {
|
|
||||||
// Override this method
|
|
||||||
}
|
|
||||||
|
|
||||||
protected configureGlobalErrorHandling(server: express.Application) {
|
|
||||||
const apiLogger = this.getApiLogger()
|
|
||||||
server.use(new middleware.ErrorPageHandler(apiLogger).handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
createAsyncRouter<T extends IRoutes>(): AsyncRouter<T> {
|
|
||||||
return new AsyncRouter<T>()
|
|
||||||
}
|
|
||||||
|
|
||||||
createTransactionalRouter<T extends IRoutes>(): AsyncRouter<T> {
|
|
||||||
return new TransactionalRouter<T>(this.transactionManager)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,16 +1,15 @@
|
|||||||
import assert from 'assert'
|
import assert from 'assert'
|
||||||
import {AddressInfo} from 'net'
|
import { createNamespace, Namespace } from 'cls-hooked'
|
||||||
import {Application} from './Application'
|
import { Server } from 'http'
|
||||||
import {Database} from '../database/Database'
|
import { AddressInfo } from 'net'
|
||||||
import {IApplication} from './IApplication'
|
import { Database } from '../database/Database'
|
||||||
import {IBootstrap} from './IBootstrap'
|
import { IDatabase } from '../database/IDatabase'
|
||||||
import {IConfig} from './IConfig'
|
import { loggerFactory, SqlLogger } from '../logger'
|
||||||
import {IDatabase} from '../database/IDatabase'
|
|
||||||
import {Server} from 'http'
|
|
||||||
import {SqlLogger, loggerFactory} from '../logger'
|
|
||||||
import {createNamespace, Namespace} from 'cls-hooked'
|
|
||||||
import { configureApplication } from './configureApplication'
|
import { configureApplication } from './configureApplication'
|
||||||
import { createApplication } from './createApplication'
|
import { createApplication } from './createApplication'
|
||||||
|
import { IApplication } from './IApplication'
|
||||||
|
import { IBootstrap } from './IBootstrap'
|
||||||
|
import { IConfig } from './IConfig'
|
||||||
|
|
||||||
export class Bootstrap implements IBootstrap {
|
export class Bootstrap implements IBootstrap {
|
||||||
protected server?: Server
|
protected server?: Server
|
||||||
|
|||||||
@ -4,21 +4,10 @@ import { ILogger } from '@rondo.dev/logger'
|
|||||||
import { IServices } from './IServices'
|
import { IServices } from './IServices'
|
||||||
import { RequestHandlerParams, ErrorRequestHandler } from 'express-serve-static-core'
|
import { RequestHandlerParams, ErrorRequestHandler } from 'express-serve-static-core'
|
||||||
|
|
||||||
export interface IFramework {
|
export interface IApplicationMiddleware {
|
||||||
readonly middleware: RequestHandlerParams[]
|
path: string
|
||||||
// TODO remove app, i believe this is used in tests
|
handle: RequestHandlerParams[]
|
||||||
readonly app: RequestHandlerParams[]
|
error?: ErrorRequestHandler
|
||||||
readonly api: RequestHandlerParams[]
|
|
||||||
readonly apiError: ErrorRequestHandler
|
|
||||||
readonly frontend: RequestHandlerParams[]
|
|
||||||
readonly error: ErrorRequestHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IFrameworkPaths {
|
|
||||||
readonly middleware: string
|
|
||||||
readonly app: string
|
|
||||||
readonly api: string
|
|
||||||
readonly frontend: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IApplicationConfig {
|
export interface IApplicationConfig {
|
||||||
@ -26,6 +15,6 @@ export interface IApplicationConfig {
|
|||||||
readonly database: IDatabase
|
readonly database: IDatabase
|
||||||
readonly logger: ILogger
|
readonly logger: ILogger
|
||||||
readonly services: IServices
|
readonly services: IServices
|
||||||
readonly paths?: Partial<IFrameworkPaths>
|
readonly globalErrorHandler: ErrorRequestHandler
|
||||||
readonly framework: IFramework
|
readonly framework: Record<string, IApplicationMiddleware>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,14 @@ import { TransactionalRouter } from '../router'
|
|||||||
import { IRoutes, IContext } from '@rondo.dev/common'
|
import { IRoutes, IContext } from '@rondo.dev/common'
|
||||||
import { Express } from 'express-serve-static-core'
|
import { Express } from 'express-serve-static-core'
|
||||||
|
|
||||||
export function configureApplication(
|
export type AppConfigurator<
|
||||||
|
T extends IApplicationConfig = IApplicationConfig
|
||||||
|
> = (
|
||||||
config: IConfig,
|
config: IConfig,
|
||||||
database: IDatabase,
|
database: IDatabase,
|
||||||
): IApplicationConfig {
|
) => T
|
||||||
|
|
||||||
|
export const configureApplication: AppConfigurator = (config, database) => {
|
||||||
|
|
||||||
const logger = loggerFactory.getLogger('api')
|
const logger = loggerFactory.getLogger('api')
|
||||||
|
|
||||||
@ -33,51 +37,59 @@ export function configureApplication(
|
|||||||
const createTransactionalRouter = <T extends IRoutes>() =>
|
const createTransactionalRouter = <T extends IRoutes>() =>
|
||||||
new TransactionalRouter<T>(transactionManager)
|
new TransactionalRouter<T>(transactionManager)
|
||||||
|
|
||||||
const getContext = (req: Express.Request): IContext => ({user: req.user})
|
const globalErrorHandler = new Middleware.ErrorPageHandler(logger).handle
|
||||||
|
|
||||||
return {
|
return {
|
||||||
config,
|
config,
|
||||||
database,
|
database,
|
||||||
logger,
|
logger,
|
||||||
services,
|
services,
|
||||||
|
globalErrorHandler,
|
||||||
framework: {
|
framework: {
|
||||||
middleware: [
|
middleware: {
|
||||||
new Middleware.SessionMiddleware({
|
path: '/',
|
||||||
transactionManager,
|
handle: [
|
||||||
baseUrl: config.app.baseUrl,
|
new Middleware.SessionMiddleware({
|
||||||
sessionName: config.app.session.name,
|
transactionManager,
|
||||||
sessionSecret: config.app.session.secret,
|
baseUrl: config.app.baseUrl,
|
||||||
}).handle,
|
sessionName: config.app.session.name,
|
||||||
new Middleware.RequestLogger(logger).handle,
|
sessionSecret: config.app.session.secret,
|
||||||
json(),
|
}).handle,
|
||||||
cookieParser(config.app.session.secret),
|
new Middleware.RequestLogger(logger).handle,
|
||||||
new Middleware.CSRFMiddleware({
|
json(),
|
||||||
baseUrl: config.app.baseUrl,
|
cookieParser(config.app.session.secret),
|
||||||
cookieName: config.app.session.name + '_csrf',
|
new Middleware.CSRFMiddleware({
|
||||||
}).handle,
|
baseUrl: config.app.baseUrl,
|
||||||
new Middleware.Transaction(database.namespace).handle,
|
cookieName: config.app.session.name + '_csrf',
|
||||||
authenticator.handle,
|
}).handle,
|
||||||
],
|
new Middleware.Transaction(database.namespace).handle,
|
||||||
app: [routes.application],
|
authenticator.handle,
|
||||||
api: [
|
],
|
||||||
new routes.LoginRoutes(
|
},
|
||||||
services.userService,
|
app: {
|
||||||
authenticator,
|
path: '/app',
|
||||||
createTransactionalRouter(),
|
handle: [routes.application],
|
||||||
).handle,
|
},
|
||||||
new routes.UserRoutes(
|
api: {
|
||||||
services.userService,
|
path: '/api',
|
||||||
createTransactionalRouter(),
|
handle: [
|
||||||
).handle,
|
new routes.LoginRoutes(
|
||||||
new Team.TeamRoutes(
|
services.userService,
|
||||||
services.teamService,
|
authenticator,
|
||||||
services.userPermissions,
|
createTransactionalRouter(),
|
||||||
createTransactionalRouter(),
|
).handle,
|
||||||
).handle,
|
new routes.UserRoutes(
|
||||||
],
|
services.userService,
|
||||||
apiError: new Middleware.ErrorApiHandler(logger).handle,
|
createTransactionalRouter(),
|
||||||
frontend: [],
|
).handle,
|
||||||
error: new Middleware.ErrorPageHandler(logger).handle,
|
new Team.TeamRoutes(
|
||||||
|
services.teamService,
|
||||||
|
services.userPermissions,
|
||||||
|
createTransactionalRouter(),
|
||||||
|
).handle,
|
||||||
|
],
|
||||||
|
error: new Middleware.ErrorApiHandler(logger).handle,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,37 +1,28 @@
|
|||||||
import { IApplicationConfig, IFrameworkPaths } from './IApplicationConfig'
|
import { IApplicationConfig } from './IApplicationConfig'
|
||||||
import { IApplication } from './IApplication'
|
import { IApplication } from './IApplication'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
|
||||||
export const defaultPaths: IFrameworkPaths = {
|
|
||||||
middleware: '/',
|
|
||||||
app: '/app',
|
|
||||||
api: '/api',
|
|
||||||
frontend: '/',
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createApplication(appConfig: IApplicationConfig): IApplication {
|
export function createApplication(appConfig: IApplicationConfig): IApplication {
|
||||||
const {config, database, framework} = appConfig
|
const {config, database, framework} = appConfig
|
||||||
const server = express()
|
const server = express()
|
||||||
|
|
||||||
const paths = {
|
|
||||||
...defaultPaths,
|
|
||||||
...(appConfig.paths || {}),
|
|
||||||
}
|
|
||||||
|
|
||||||
server.set('trust proxy', 1)
|
server.set('trust proxy', 1)
|
||||||
server.disable('x-powered-by')
|
server.disable('x-powered-by')
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
router.use(paths.middleware, ...framework.middleware)
|
|
||||||
router.use(paths.app, ...framework.app)
|
Object.keys(framework)
|
||||||
router.use(paths.api, ...framework.api)
|
.forEach(name => {
|
||||||
router.use(paths.api, framework.apiError)
|
const {path, handle, error} = framework[name]
|
||||||
if (framework.frontend.length) {
|
router.use(path, ...handle)
|
||||||
router.use(paths.frontend, ...framework.frontend)
|
if (error) {
|
||||||
}
|
router.use(path, error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
server.use(config.app.context, router)
|
server.use(config.app.context, router)
|
||||||
server.use(framework.error)
|
server.use(appConfig.globalErrorHandler)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
server,
|
server,
|
||||||
database,
|
database,
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
export * from './Application'
|
export * from './Application'
|
||||||
export * from './Bootstrap'
|
export * from './Bootstrap'
|
||||||
export * from './IApplication'
|
export * from './IApplication'
|
||||||
|
export * from './IApplicationConfig'
|
||||||
export * from './IConfig'
|
export * from './IConfig'
|
||||||
export * from './IServices'
|
export * from './IServices'
|
||||||
|
export * from './configureApplication'
|
||||||
|
export * from './createApplication'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user