Task: Add reflection metadata for decorators and add basic implements for controller and express application and constants and app
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
a6546b7676
commit
67c94211e7
@ -24,6 +24,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
|
"@types/node": "^16.9.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.30.0",
|
"@typescript-eslint/eslint-plugin": "^4.30.0",
|
||||||
"@typescript-eslint/parser": "^4.30.0",
|
"@typescript-eslint/parser": "^4.30.0",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
@ -36,12 +37,12 @@
|
|||||||
"lint-staged": "^11.1.2",
|
"lint-staged": "^11.1.2",
|
||||||
"prettier": "2.3.2",
|
"prettier": "2.3.2",
|
||||||
"ts-node-dev": "^1.1.8",
|
"ts-node-dev": "^1.1.8",
|
||||||
"typescript": "^4.4.2",
|
"typescript": "^4.4.2"
|
||||||
"@types/node": "^16.9.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@cubetiq/ts-common": "1.0.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"@cubetiq/ts-common": "1.0.0"
|
"reflect-metadata": "^0.1.13"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"**/*": "prettier --write --ignore-unknown"
|
"**/*": "prettier --write --ignore-unknown"
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
// app config
|
// app config
|
||||||
import "./dotenv"
|
import "./dotenv"
|
||||||
|
|
||||||
|
// reflection metadata for decorator
|
||||||
|
import "reflect-metadata"
|
||||||
|
|
||||||
// core app
|
// core app
|
||||||
import "./server"
|
import "./server"
|
@ -1,23 +0,0 @@
|
|||||||
import express, { Application as ExpressApp } from "express"
|
|
||||||
|
|
||||||
class Application {
|
|
||||||
private readonly _instance: ExpressApp
|
|
||||||
|
|
||||||
get instance(): ExpressApp {
|
|
||||||
return this._instance
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this._instance = express()
|
|
||||||
this._instance.use(express.json())
|
|
||||||
this.registerRoutes()
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerRoutes(): void {
|
|
||||||
this._instance.get("/", (req, res) => {
|
|
||||||
res.send("Hello World!")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Application()
|
|
@ -1,3 +0,0 @@
|
|||||||
const index = (req: any, res: any) => {
|
|
||||||
res.send("Hello World!")
|
|
||||||
}
|
|
52
src/application.ts
Normal file
52
src/application.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import express, { Application as ExpressApp, Handler } from "express"
|
||||||
|
import { controllers } from "./controller"
|
||||||
|
import { RouteHandler } from "./decorators/handlers.decorator"
|
||||||
|
import { MetadataKeys } from "./constants/metadata.keys"
|
||||||
|
|
||||||
|
class Application {
|
||||||
|
private readonly _instance: ExpressApp
|
||||||
|
|
||||||
|
get instance(): ExpressApp {
|
||||||
|
return this._instance
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._instance = express()
|
||||||
|
this.registerRoutes()
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerRoutes(): void {
|
||||||
|
const info: Array<{ api: string; handler: string }> = []
|
||||||
|
|
||||||
|
controllers.forEach((controller) => {
|
||||||
|
const controllerInstance: { [handlerName: string]: Handler } =
|
||||||
|
new controller() as any
|
||||||
|
const basePath: string = Reflect.getMetadata(
|
||||||
|
MetadataKeys.BASE_PATH,
|
||||||
|
controller
|
||||||
|
)
|
||||||
|
const routers: RouteHandler[] = Reflect.getMetadata(
|
||||||
|
MetadataKeys.ROUTERS,
|
||||||
|
controller
|
||||||
|
)
|
||||||
|
const exRouter = express.Router()
|
||||||
|
|
||||||
|
routers.forEach(({ method, path, handlerName }) => {
|
||||||
|
exRouter[method](
|
||||||
|
path,
|
||||||
|
controllerInstance[String(handlerName)]
|
||||||
|
).bind(controllerInstance)
|
||||||
|
info.push({
|
||||||
|
api: `${method.toLocaleUpperCase()} ${basePath + path}`,
|
||||||
|
handler: `${controller.name}.${String(handlerName)}`,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this._instance.use(basePath, exRouter)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.table(info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Application()
|
4
src/constants/metadata.keys.ts
Normal file
4
src/constants/metadata.keys.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum MetadataKeys {
|
||||||
|
BASE_PATH = "base_path",
|
||||||
|
ROUTERS = "routers",
|
||||||
|
}
|
13
src/controller/index.controller.ts
Normal file
13
src/controller/index.controller.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Request, Response } from "express"
|
||||||
|
import Controller from "../decorators/controller.decorator"
|
||||||
|
import { Get } from "../decorators/handlers.decorator"
|
||||||
|
|
||||||
|
@Controller("/hello")
|
||||||
|
export default class IndexController {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
@Get("")
|
||||||
|
public index(req: Request, res: Response) {
|
||||||
|
res.send(`Hello Index`)
|
||||||
|
}
|
||||||
|
}
|
3
src/controller/index.ts
Normal file
3
src/controller/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import IndexController from "./index.controller"
|
||||||
|
|
||||||
|
export const controllers = [IndexController]
|
9
src/decorators/controller.decorator.ts
Normal file
9
src/decorators/controller.decorator.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { MetadataKeys } from "../constants/metadata.keys"
|
||||||
|
|
||||||
|
const Controller = (basePath: string): ClassDecorator => {
|
||||||
|
return (target: any) => {
|
||||||
|
Reflect.defineMetadata(MetadataKeys.BASE_PATH, basePath, target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Controller
|
41
src/decorators/handlers.decorator.ts
Normal file
41
src/decorators/handlers.decorator.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { MetadataKeys } from "../constants/metadata.keys"
|
||||||
|
|
||||||
|
export enum Method {
|
||||||
|
GET = "get",
|
||||||
|
POST = "post",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RouteHandler {
|
||||||
|
method: Method
|
||||||
|
path: string
|
||||||
|
handlerName: string | symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
const methodDecoratorFactory = (method: Method) => {
|
||||||
|
return (path: string): MethodDecorator => {
|
||||||
|
return (target: any, propertyKey: string | symbol): void => {
|
||||||
|
const controllerClass = target.constructor
|
||||||
|
const routers: RouteHandler[] = Reflect.hasMetadata(
|
||||||
|
MetadataKeys.ROUTERS,
|
||||||
|
controllerClass
|
||||||
|
)
|
||||||
|
? Reflect.getMetadata(MetadataKeys.ROUTERS, controllerClass)
|
||||||
|
: []
|
||||||
|
|
||||||
|
routers.push({
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
handlerName: propertyKey,
|
||||||
|
})
|
||||||
|
|
||||||
|
Reflect.defineMetadata(
|
||||||
|
MetadataKeys.ROUTERS,
|
||||||
|
routers,
|
||||||
|
controllerClass
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Get = methodDecoratorFactory(Method.GET)
|
||||||
|
export const Post = methodDecoratorFactory(Method.POST)
|
@ -1,7 +1,7 @@
|
|||||||
import { createServer } from "http"
|
import { createServer } from "http"
|
||||||
import { SERVER_PORT } from "./app.config"
|
import { SERVER_PORT } from "./app.config"
|
||||||
import { info } from "@cubetiq/ts-common/dist/log"
|
import { info } from "@cubetiq/ts-common/dist/log"
|
||||||
import application from "./app/application"
|
import application from "./application"
|
||||||
|
|
||||||
// get current host id
|
// get current host id
|
||||||
const hostId = `${require("os").hostname()}#${process.pid}`
|
const hostId = `${require("os").hostname()}#${process.pid}`
|
||||||
@ -11,7 +11,7 @@ const app = application.instance
|
|||||||
const httpServer = createServer(app)
|
const httpServer = createServer(app)
|
||||||
|
|
||||||
info(
|
info(
|
||||||
`Application server running on: ${hostId} at: http://0.0.0.0:${SERVER_PORT} and started at: ${startedAt}`
|
`Application server running on: ${hostId} at port: ${SERVER_PORT} and started at: ${startedAt}`
|
||||||
)
|
)
|
||||||
httpServer.listen(SERVER_PORT)
|
httpServer.listen(SERVER_PORT)
|
||||||
|
|
||||||
|
1
src/utils/utils.ts
Normal file
1
src/utils/utils.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
// nothing here for now
|
@ -1,15 +1,16 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"lib": ["ES2015"],
|
"lib": ["ES2015"],
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true,
|
||||||
},
|
"experimentalDecorators": true
|
||||||
"exclude": ["node_modules"]
|
},
|
||||||
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user