Skip to content

Commit b3e22a0

Browse files
committed
feat: allow lazy imports when registering middleware
1 parent ec1327e commit b3e22a0

File tree

12 files changed

+234
-73
lines changed

12 files changed

+234
-73
lines changed

adonis-typings/middleware.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,22 @@ declare module '@ioc:Adonis/Core/Middleware' {
1111
import { IocContract } from '@adonisjs/fold'
1212
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
1313

14+
export type DefaultExport<T> = Promise<{ default: T }>
15+
16+
/**
17+
* Shape of the middleware class
18+
*/
19+
export interface MiddlewareConstructorContract {
20+
new (...args: any[]): {
21+
handle(ctx: HttpContextContract, next: () => void, ...options: any[]): any
22+
}
23+
}
24+
1425
/**
1526
* Input middleware node must be function or a string pointing
1627
* to the IoC container
1728
*/
18-
export type MiddlewareHandler =
19-
| string
20-
| ((ctx: HttpContextContract, next: () => Promise<void>, args?: string[]) => Promise<void>)
29+
export type MiddlewareHandler = string | (() => DefaultExport<MiddlewareConstructorContract>)
2130

2231
/**
2332
* Shape of resolved middleware. This information is
@@ -26,6 +35,11 @@ declare module '@ioc:Adonis/Core/Middleware' {
2635
export type ResolvedMiddlewareHandler =
2736
| {
2837
type: 'function'
38+
value: (ctx: HttpContextContract, next: () => void, ...options: any[]) => any
39+
args: string[]
40+
}
41+
| {
42+
type: 'lazy-import'
2943
value: Exclude<MiddlewareHandler, string>
3044
args: string[]
3145
}

adonis-typings/route.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
declare module '@ioc:Adonis/Core/Route' {
1111
import { MacroableConstructorContract } from 'macroable'
1212
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
13-
import { MiddlewareHandler, ResolvedMiddlewareHandler } from '@ioc:Adonis/Core/Middleware'
13+
import { ResolvedMiddlewareHandler } from '@ioc:Adonis/Core/Middleware'
1414

1515
/**
1616
* Route.where param matcher shape
@@ -26,7 +26,14 @@ declare module '@ioc:Adonis/Core/Route' {
2626
/**
2727
* The shape of the route handler
2828
*/
29-
export type RouteHandler = ((ctx: HttpContextContract) => Promise<any>) | string
29+
export type RouteHandler = ((ctx: HttpContextContract) => any) | string
30+
31+
/**
32+
* Middleware handler attached to the route.
33+
*/
34+
export type RouteMiddlewareHandler =
35+
| string
36+
| ((ctx: HttpContextContract, next: () => void, ...options: any[]) => any)
3037

3138
/**
3239
* Node after resolving controller.method binding from the route
@@ -75,7 +82,7 @@ declare module '@ioc:Adonis/Core/Route' {
7582
* leaves the type to `any` for the consumer to decide the
7683
* shape of the middleware
7784
*/
78-
middleware: MiddlewareHandler[]
85+
middleware: RouteMiddlewareHandler[]
7986

8087
/**
8188
* Any custom runtime properties to be added to the route
@@ -212,7 +219,10 @@ declare module '@ioc:Adonis/Core/Route' {
212219
* is true, then middleware will be added to start of the existing
213220
* middleware. The option is exposed for [[RouteGroup]]
214221
*/
215-
middleware(middleware: MiddlewareHandler | MiddlewareHandler[], prepend?: boolean): this
222+
middleware(
223+
middleware: RouteMiddlewareHandler | RouteMiddlewareHandler[],
224+
prepend?: boolean
225+
): this
216226

217227
/**
218228
* Give memorizable name to the route. This is helpful, when you
@@ -274,9 +284,9 @@ declare module '@ioc:Adonis/Core/Route' {
274284
*/
275285
middleware(
276286
middleware: {
277-
[P in ResourceRouteNames]?: MiddlewareHandler | MiddlewareHandler[]
287+
[P in ResourceRouteNames]?: RouteMiddlewareHandler | RouteMiddlewareHandler[]
278288
} & {
279-
'*'?: MiddlewareHandler | MiddlewareHandler[]
289+
'*'?: RouteMiddlewareHandler | RouteMiddlewareHandler[]
280290
}
281291
): this
282292

@@ -355,7 +365,7 @@ declare module '@ioc:Adonis/Core/Route' {
355365
* }).middleware(['auth'])
356366
* ```
357367
*/
358-
middleware(middleware: MiddlewareHandler | MiddlewareHandler[]): this
368+
middleware(middleware: RouteMiddlewareHandler | RouteMiddlewareHandler[]): this
359369

360370
/**
361371
* Define namespace for all the routes inside the group.

benchmarks/fastify.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
const fastify = require('fastify')()
22

3-
fastify.get('/', (_, reply) => {
4-
reply.send({ hello: 'world' })
5-
})
3+
fastify.register(require('middie')).then(() => {
4+
fastify.get('/', (_, reply) => {
5+
reply.send({ hello: 'world' })
6+
})
67

7-
fastify.listen(3000, () => {
8-
console.log('listening on 3000')
8+
fastify.listen(3000, () => {
9+
console.log('listening on 3000')
10+
})
911
})

package-lock.json

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"http-status-codes": "^2.1.4",
6161
"husky": "^5.0.9",
6262
"japa": "^3.1.1",
63+
"middie": "^5.2.0",
6364
"mrm": "^2.5.18",
6465
"np": "^7.3.0",
6566
"pem": "^1.14.4",

src/MiddlewareStore/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export class MiddlewareStore implements MiddlewareStoreContract {
5555
*/
5656
private resolver: IocResolverContract<any>
5757

58-
constructor(container: IocContract) {
58+
constructor(private container: IocContract) {
5959
this.resolver = container.getResolver()
6060
}
6161

@@ -71,7 +71,7 @@ export class MiddlewareStore implements MiddlewareStoreContract {
7171
private resolveMiddleware(middleware: MiddlewareHandler): ResolvedMiddlewareHandler {
7272
return typeof middleware === 'function'
7373
? {
74-
type: 'function',
74+
type: 'lazy-import',
7575
value: middleware,
7676
args: [],
7777
}
@@ -128,6 +128,16 @@ export class MiddlewareStore implements MiddlewareStoreContract {
128128

129129
const args: any[] = [params[0], params[1]]
130130
args.push(middleware.args)
131+
132+
/**
133+
* Handling the lazily imported middleware
134+
*/
135+
if (middleware.type === 'lazy-import') {
136+
const middlewareClass = await middleware.value()
137+
const middlewareInstance = await this.container.makeAsync(middlewareClass.default)
138+
return this.container.callAsync(middlewareInstance, 'handle', args)
139+
}
140+
131141
return this.resolver.call(middleware, undefined, args)
132142
}
133143
}

src/Router/Group.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
/// <reference path="../../adonis-typings/index.ts" />
1111

1212
import { Macroable } from 'macroable'
13-
import { MiddlewareHandler } from '@ioc:Adonis/Core/Middleware'
14-
import { RouteGroupContract, RouteParamMatcher } from '@ioc:Adonis/Core/Route'
13+
import {
14+
RouteGroupContract,
15+
RouteParamMatcher,
16+
RouteMiddlewareHandler,
17+
} from '@ioc:Adonis/Core/Route'
1518

1619
import { Route } from './Route'
1720
import { BriskRoute } from './BriskRoute'
@@ -141,7 +144,7 @@ export class RouteGroup extends Macroable implements RouteGroupContract {
141144
* }).middleware(['auth'])
142145
* ```
143146
*/
144-
public middleware(middleware: MiddlewareHandler | MiddlewareHandler[]): this {
147+
public middleware(middleware: RouteMiddlewareHandler | RouteMiddlewareHandler[]): this {
145148
this.routes.forEach((route) => this.invoke(route, 'middleware', [middleware, true]))
146149
return this
147150
}

src/Router/Resource.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ import { singular } from 'pluralize'
1313
import { Macroable } from 'macroable'
1414
import { string } from '@poppinss/utils/build/helpers'
1515

16-
import { MiddlewareHandler } from '@ioc:Adonis/Core/Middleware'
1716
import {
1817
RouteParamMatcher,
1918
ResourceRouteNames,
2019
RouteMatchersNode,
2120
RouteResourceContract,
21+
RouteMiddlewareHandler,
2222
} from '@ioc:Adonis/Core/Route'
2323

2424
import { Route } from './Route'
@@ -131,9 +131,9 @@ export class RouteResource extends Macroable implements RouteResourceContract {
131131
*/
132132
public middleware(
133133
middleware: {
134-
[P in ResourceRouteNames]?: MiddlewareHandler | MiddlewareHandler[]
134+
[P in ResourceRouteNames]?: RouteMiddlewareHandler | RouteMiddlewareHandler[]
135135
} & {
136-
'*'?: MiddlewareHandler | MiddlewareHandler[]
136+
'*'?: RouteMiddlewareHandler | RouteMiddlewareHandler[]
137137
}
138138
): this {
139139
for (let name in middleware) {

src/Router/Route.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import {
1717
RouteHandler,
1818
RouteMatchersNode,
1919
RouteParamMatcher,
20+
RouteMiddlewareHandler,
2021
} from '@ioc:Adonis/Core/Route'
21-
import { MiddlewareHandler } from '@ioc:Adonis/Core/Middleware'
2222

2323
import { dropSlash } from '../helpers'
2424

@@ -64,7 +64,7 @@ export class Route extends Macroable implements RouteContract {
6464
/**
6565
* An array of middleware. Added using `middleware` function
6666
*/
67-
private routeMiddleware: MiddlewareHandler[] = []
67+
private routeMiddleware: RouteMiddlewareHandler[] = []
6868

6969
/**
7070
* Storing the namespace explicitly set using `route.namespace` method
@@ -171,7 +171,10 @@ export class Route extends Macroable implements RouteContract {
171171
* is true, then middleware will be added to start of the existing
172172
* middleware. The option is exposed for [[RouteGroup]]
173173
*/
174-
public middleware(middleware: MiddlewareHandler | MiddlewareHandler[], prepend = false): this {
174+
public middleware(
175+
middleware: RouteMiddlewareHandler | RouteMiddlewareHandler[],
176+
prepend = false
177+
): this {
175178
middleware = Array.isArray(middleware) ? middleware : [middleware]
176179
this.routeMiddleware = prepend
177180
? middleware.concat(this.routeMiddleware)

test/middleware-store.spec.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@ import { MiddlewareStore } from '../src/MiddlewareStore'
1414
test.group('Middleware', () => {
1515
test('register global middleware', (assert) => {
1616
const middleware = new MiddlewareStore(new Ioc())
17-
async function handler() {}
17+
class GlobalMiddleware {
18+
public async handle() {}
19+
}
20+
21+
const handler = () => Promise.resolve({ default: GlobalMiddleware })
1822

1923
middleware.register([handler])
2024
assert.deepEqual(middleware.get(), [
2125
{
22-
type: 'function',
26+
type: 'lazy-import',
2327
value: handler,
2428
args: [],
2529
},
@@ -28,21 +32,29 @@ test.group('Middleware', () => {
2832

2933
test('register named middleware', (assert) => {
3034
const middleware = new MiddlewareStore(new Ioc())
31-
async function handler() {}
35+
class GlobalMiddleware {
36+
public async handle() {}
37+
}
38+
39+
const handler = () => Promise.resolve({ default: GlobalMiddleware })
3240

3341
middleware.registerNamed({ auth: handler })
3442
assert.deepEqual(middleware['named'], {
35-
auth: { type: 'function', value: handler, args: [] },
43+
auth: { type: 'lazy-import', value: handler, args: [] },
3644
})
3745
})
3846

3947
test('get named middleware', (assert) => {
4048
const middleware = new MiddlewareStore(new Ioc())
41-
async function handler() {}
49+
class GlobalMiddleware {
50+
public async handle() {}
51+
}
52+
53+
const handler = () => Promise.resolve({ default: GlobalMiddleware })
4254

4355
middleware.registerNamed({ auth: handler })
4456
assert.deepEqual(middleware.getNamed('auth'), {
45-
type: 'function',
57+
type: 'lazy-import',
4658
value: handler,
4759
args: [],
4860
})
@@ -55,12 +67,17 @@ test.group('Middleware', () => {
5567

5668
test('invoke resolved middleware', async (assert) => {
5769
const stack: any[] = []
58-
async function middlewareFn() {
59-
stack.push('middlewareFn')
70+
71+
class GlobalMiddleware {
72+
public async handle() {
73+
stack.push('middlewareFn')
74+
}
6075
}
6176

77+
const handler = () => Promise.resolve({ default: GlobalMiddleware })
78+
6279
const middleware = new MiddlewareStore(new Ioc())
63-
middleware.register([middlewareFn])
80+
middleware.register([handler])
6481
await middleware.invokeMiddleware(middleware.get()[0], [] as any)
6582
assert.deepEqual(stack, ['middlewareFn'])
6683
})

0 commit comments

Comments
 (0)