Demo

Middleware

Controller များတွင် auth၊ permission နှင့် audit middleware ကို တပ်ဆင်အသုံးပြုရပါသည်။ Plugin တစ်ခုလုံးအတွက် @Module ၏ globalFilter / globalExceptionsFilter ဖြင့် မှတ်ပုံတင်နိုင်ပြီး၊ @Middleware ဖြင့် ကိုယ်ပိုင် middleware လည်း ရေးနိုင်ပါသည်။

အသုံးပြုပုံ

Controller class တစ်ခုလုံး (route အားလုံး) သို့မဟုတ် method တစ်ခုတည်းတွင် decorate လုပ်ရပါသည်။ Middleware များကို အလုပ်လုပ်စေလိုသော အစဉ်အတိုင်း စီရပါသည် — admin API များတွင် auth ကို permission မတိုင်မီ အရင် တပ်လေ့ရှိပါသည်။ App တစ်ခုလုံး၏ request တိုင်းတွင် လိုအပ်ပါက root @Module ၏ globalFilter ကို အသုံးပြုရပါသည်။

TSXusage
1import { 2 AuditLogMiddleware, 3 AuthenticatedUserOnly, 4 CheckAPIPermission, 5 Controller, 6 Get, 7 ResponseDto, 8} from "@quan-erp/shared-backend-core"; 9 10@Controller("/admin-dashboard") 11export class AdminDashboardController { 12 @Get("/stats") 13 @AuthenticatedUserOnly() 14 @CheckAPIPermission() 15 @AuditLogMiddleware((req) => `View stats`) 16 async getStats() { 17 return ResponseDto.ok(data); 18 } 19}

Builtin middleware

  • @AuthenticatedUserOnly() — အကောင့်မဝင်သော caller ကို 401 ဖြင့် ငြင်းပယ်ပါသည် — login လိုအပ်သော endpoint တိုင်းတွင် အသုံးပြုရပါသည်
  • @CheckAPIPermission() — လက်ရှိ method နှင့် URL အတွက် အသုံးပြုသူ၏ အခန်းကဏ္ဍ ခွင့်ပြု API ကို စစ်ဆေးပါသည် — admin route တွင် @AuthenticatedUserOnly နှင့် တွဲသုံးရပါသည်
  • @AuditLogMiddleware(action) — static string သို့မဟုတ် (req) => string ဖြင့် ထိခိုက်လွယ်သော လုပ်ဆောင်ချက်များ၏ audit မှတ်တမ်း ရေးပါသည်
TSXaudit
1import { 2 AuditLogMiddleware, 3 Controller, 4 Get, 5 Put, 6} from "@quan-erp/shared-backend-core"; 7 8@Controller("/branch") 9export class BranchController { 10 @AuditLogMiddleware("View all branches") 11 @Get("/") 12 async getAll() { /* … */ } 13 14 @AuditLogMiddleware((req) => `Update branch ${req.params.id}`) 15 @Put("/:id") 16 async update() { /* … */ } 17}

Global middleware (module)

Root @Module တွင် filter များကို မှတ်ပုံတင်ပါက controller တစ်ခုတည်းမဟုတ်ဘဲ request တိုင်းတွင် အလုပ်လုပ်ပါသည်။ Request အတွက် globalFilter၊ အမှားကိုင်တွယ်ရန် globalExceptionsFilter ကို အသုံးပြုရပါသည်။ Plugin ကို uninstall လုပ်သောအခါ core က ၎င်းတို့ကို အလိုအလျောက် ဖြုတ်ပေးပါသည်။

  • globalFilter: { position, handler }[] — app တစ်ခုလုံးအတွက် request middleware
  • globalExceptionsFilter: handler[] — app တစ်ခုလုံးအတွက် exception middleware (IExceptionMiddleware)
  • MiddlewarePosition.BEFORE_ROOT_ROUTE — plugin root route မတိုင်မီ အလုပ်လုပ်ပါသည် (auth / resolve-user / logging အတွက် သင့်တော်ပါသည်)
  • MiddlewarePosition.AFTER_ROOT_ROUTE — root stack ပြီးနောက် အလုပ်လုပ်ပါသည်
  • Handler — Express RequestHandler သို့မဟုတ် IExpressMiddleware / IExceptionMiddleware ကို implement လုပ်သော class
  • Class middleware တိုင်းတွင် @MiddlewareMetadata({ plugin: metadata.name }) မဖြစ်မနေ လိုအပ်ပါသည်
TSXglobalFilter on @Module
1import { 2 MiddlewareMetadata, 3 MiddlewarePosition, 4 Module, 5} from "@quan-erp/shared-backend-core"; 6import type { 7 IExceptionMiddleware, 8 IExpressMiddleware, 9} from "@quan-erp/shared-backend-core"; 10import type { NextFunction, Request, Response } from "express"; 11import metadata from "../../module.metadata.json" with { type: "json" }; 12import { MyController } from "./my.controller.js"; 13import { MyService } from "./my.service.js"; 14 15@MiddlewareMetadata({ plugin: metadata.name }) 16export class RequestIdMiddleware implements IExpressMiddleware { 17 handler(req: Request, res: Response, next: NextFunction) { 18 res.setHeader("x-request-plugin", metadata.name); 19 return next(); 20 } 21} 22 23@MiddlewareMetadata({ plugin: metadata.name }) 24export class PluginErrorFilter implements IExceptionMiddleware { 25 handler(error: Error, req: Request, res: Response, next: NextFunction) { 26 if (res.headersSent) return next(error); 27 res.status(500).json({ message: error.message }); 28 } 29} 30 31@Module({ 32 name: metadata.name, 33 providers: [MyService], 34 controllers: [MyController], 35 entities: [], 36 globalFilter: [ 37 { 38 position: MiddlewarePosition.BEFORE_ROOT_ROUTE, 39 handler: RequestIdMiddleware, 40 }, 41 ], 42 globalExceptionsFilter: [PluginErrorFilter], 43}) 44export class MyPluginModule {}

ကိုယ်ပိုင် middleware ဖန်တီးခြင်း

Controller သို့မဟုတ် method အတွက် Middleware(...) ကို decorator အဖြစ် ထုပ်ပိုးရေးရပါသည်။ DI သိသော handler သို့မဟုတ် globalFilter အတွက် IExpressMiddleware / IExceptionMiddleware ကို implement လုပ်နိုင်ပါသည်။ Class middleware တိုင်းတွင် @MiddlewareMetadata({ plugin: metadata.name }) မဖြစ်မနေ ကြေညာရပါသည် — core က မှန်ကန်သော plugin DI scope တွင် resolve လုပ်ရန်ဖြစ်ပါသည်။ Route ပေါ်တွင် @MyDecorator() သို့မဟုတ် @Middleware(MyClass) ဖြင့် တပ်ဆင်ရပါသည်။

  • လိုအပ်ပါသည် — IExpressMiddleware / IExceptionMiddleware class တိုင်းတွင် @MiddlewareMetadata({ plugin: metadata.name })
  • Decorator ပုံစံ — factory မှ Middleware(async (req, res, next) => { … }) ပြန်ပေးရပါသည် (function handler ဖြစ်၍ MiddlewareMetadata မလိုအပ်ပါ)
  • Class ပုံစံ (IExpressMiddleware) — handler(req, res, next); @Inject သည် @Service() မလိုဘဲ အလုပ်လုပ်ပါသည်
  • Exception middleware (IExceptionMiddleware) — handler(error, req, res, next)
  • Middleware ကို တစ်ခုတည်းသော တာဝန်အပေါ် အာရုံစိုက်ထားရပါသည် — လုပ်ငန်းစည်းမျဉ်းများကို ဖြစ်နိုင်လျှင် service တွင် ထားရှိရပါသည်
TSXdecorator middleware
1import { 2 HttpStatus, 3 Middleware, 4 ResponseDto, 5} from "@quan-erp/shared-backend-core"; 6 7export function MyCustomAuth(): MethodDecorator & ClassDecorator { 8 return Middleware(async (req, res, next) => { 9 if (req.headers["x-custom-header"] === "secret-value") return next(); 10 return res 11 .status(HttpStatus.UNAUTHORIZED) 12 .json(ResponseDto.error("Unauthorized", HttpStatus.UNAUTHORIZED)); 13 }); 14}
TSXclass middleware
1import type { NextFunction, Request, Response } from "express"; 2import { 3 Controller, 4 Inject, 5 Middleware, 6 MiddlewareMetadata, 7} from "@quan-erp/shared-backend-core"; 8import type { IExpressMiddleware } from "@quan-erp/shared-backend-core"; 9import metadata from "../../module.metadata.json" with { type: "json" }; 10import { MyService } from "./my.service.js"; 11 12@MiddlewareMetadata({ plugin: metadata.name }) 13export class MyComplexMiddleware implements IExpressMiddleware { 14 @Inject(MyService) 15 private myService: MyService; 16 17 async handler(req: Request, res: Response, next: NextFunction) { 18 if (await this.myService.validate(req.body)) return next(); 19 res.status(400).send("Invalid request"); 20 } 21} 22 23@Middleware(MyComplexMiddleware) 24@Controller("/complex") 25export class ComplexController {}