forked from lukeautry/tsoa
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: allow custom middlewares for controllers and methods (lukeautry…
…#1123) * allow custom middlewares for controllers and methods * use Reflect API * use reflect-metadata * move import to index and type decorator function * better middleware typings * removed frameworks types deps * fixed tests prestep * Use Array<T> instead of T[]
- Loading branch information
Showing
17 changed files
with
274 additions
and
16 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
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
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,51 @@ | ||
type Middleware<T extends Function | Object> = T; | ||
|
||
const TSOA_MIDDLEWARES = Symbol('@tsoa:middlewares'); | ||
|
||
/** | ||
* Helper function to create a decorator | ||
* that can act as a class and method decorator. | ||
* @param fn a callback function that accepts | ||
* the subject of the decorator | ||
* either the constructor or the | ||
* method | ||
* @returns | ||
*/ | ||
function decorator(fn: (value: any) => void) { | ||
return (...args: any[]) => { | ||
// class decorator | ||
if (args.length === 1) { | ||
fn(args[0]); | ||
} else if (args.length === 3 && args[2].value) { | ||
// method decorator | ||
const descriptor = args[2] as PropertyDescriptor; | ||
if (descriptor.value) { | ||
fn(descriptor.value); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Install middlewares to the Controller or a specific method. | ||
* @param middlewares | ||
* @returns | ||
*/ | ||
export function Middlewares<T>(...mws: Array<Middleware<T>>): ClassDecorator & MethodDecorator { | ||
return decorator(target => { | ||
if (mws) { | ||
const current = fetchMiddlewares<T>(target); | ||
Reflect.defineMetadata(TSOA_MIDDLEWARES, [...current, ...mws], target); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Internal function used to retrieve installed middlewares | ||
* in controller and methods (used during routes generation) | ||
* @param target | ||
* @returns list of middlewares | ||
*/ | ||
export function fetchMiddlewares<T>(target: any): Array<Middleware<T>> { | ||
return Reflect.getMetadata(TSOA_MIDDLEWARES, target) || []; | ||
} |
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
37 changes: 37 additions & 0 deletions
37
tests/fixtures/controllers/middlewaresExpressController.ts
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,37 @@ | ||
import { Route, Get, Middlewares as GenericMiddlewares } from '@tsoa/runtime'; | ||
|
||
import type { | ||
Request as ExpressRequest, | ||
Response as ExpressResponse, | ||
NextFunction as ExpressNextFunction, | ||
RequestHandler, | ||
} from 'express'; | ||
|
||
function Middlewares(...mws: RequestHandler[]) { | ||
return GenericMiddlewares<RequestHandler>(...mws); | ||
} | ||
|
||
const middlewaresState = {}; | ||
|
||
export function stateOf(key: string): boolean | undefined { | ||
return middlewaresState[key]; | ||
} | ||
|
||
function testMiddleware(key: string) { | ||
return async (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => { | ||
middlewaresState[key] = true; | ||
next(); | ||
}; | ||
} | ||
|
||
@GenericMiddlewares<RequestHandler>( | ||
testMiddleware('route'), | ||
) | ||
@Route('MiddlewareTestExpress') | ||
export class MiddlewareExpressController { | ||
@Middlewares(testMiddleware('test1')) | ||
@Get('/test1') | ||
public async test1(): Promise<void> { | ||
return; | ||
} | ||
} |
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,33 @@ | ||
import { Route, Get, Middlewares as GenericMiddlewares } from '@tsoa/runtime'; | ||
|
||
import type { Request, ResponseToolkit, RouteOptionsPreAllOptions } from '@hapi/hapi'; | ||
|
||
function Middlewares(...mws: RouteOptionsPreAllOptions[]) { | ||
return GenericMiddlewares<RouteOptionsPreAllOptions>(...mws); | ||
} | ||
|
||
const middlewaresState = {}; | ||
|
||
export function stateOf(key: string): boolean | undefined { | ||
return middlewaresState[key]; | ||
} | ||
|
||
function testMiddleware(key: string) { | ||
return async (request: Request, h: ResponseToolkit) => { | ||
middlewaresState[key] = true; | ||
return key; | ||
}; | ||
} | ||
|
||
|
||
@GenericMiddlewares<RouteOptionsPreAllOptions>( | ||
testMiddleware('route'), | ||
) | ||
@Route('MiddlewareTestHapi') | ||
export class MiddlewareHapiController { | ||
@Middlewares(testMiddleware('test1')) | ||
@Get('/test1') | ||
public async test1(): Promise<void> { | ||
return; | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
tests/fixtures/controllers/middlewaresHierarchyController.ts
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 { Route, Get, Middlewares as GenericMiddlewares, Controller } from '@tsoa/runtime'; | ||
|
||
import type { Request, Response, NextFunction, RequestHandler } from 'express'; | ||
|
||
function Middlewares(...mws: RequestHandler[]) { | ||
return GenericMiddlewares<RequestHandler>(...mws); | ||
} | ||
|
||
const middlewaresState: string[] = []; | ||
|
||
export function state(): string[] { | ||
return middlewaresState; | ||
} | ||
|
||
function testMiddleware(key: string) { | ||
return async (req: Request, res: Response, next: NextFunction) => { | ||
middlewaresState.push(key); | ||
next(); | ||
}; | ||
} | ||
|
||
// base class with some middleware | ||
@Middlewares(testMiddleware('base')) | ||
class BaseController extends Controller {} | ||
|
||
// another one | ||
@Middlewares(testMiddleware('intermediate')) | ||
class IntermediateController extends BaseController {} | ||
|
||
// intermediate controller class without middlewares | ||
class NoopController extends IntermediateController {} | ||
|
||
@GenericMiddlewares<RequestHandler>( | ||
testMiddleware('route'), | ||
) | ||
@Route('MiddlewareHierarchyTestExpress') | ||
export class MiddlewareHierarchyTestExpress extends NoopController { | ||
@Middlewares(testMiddleware('test1')) | ||
@Get('/test1') | ||
public async test1(): Promise<void> { | ||
return; | ||
} | ||
} |
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 @@ | ||
import { Route, Get, Middlewares as GenericMiddlewares } from '@tsoa/runtime'; | ||
|
||
import type { Context as KoaContext, Next as KoaNext, Middleware } from 'koa'; | ||
|
||
function Middlewares(...mws: Middleware[]) { | ||
return GenericMiddlewares<Middleware>(...mws); | ||
} | ||
|
||
const middlewaresState = {}; | ||
|
||
export function stateOf(key: string): boolean | undefined { | ||
return middlewaresState[key]; | ||
} | ||
|
||
function testMiddleware(key: string) { | ||
return async (ctx: KoaContext, next: KoaNext) => { | ||
middlewaresState[key] = true; | ||
next(); | ||
}; | ||
} | ||
|
||
@GenericMiddlewares<Middleware>( | ||
testMiddleware('route'), | ||
) | ||
@Route('MiddlewareTestKoa') | ||
export class MiddlewareKoaController { | ||
@Middlewares(testMiddleware('test1')) | ||
@Get('/test1') | ||
public async test1(): Promise<void> { | ||
return; | ||
} | ||
} |
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
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
Oops, something went wrong.