diff --git a/src/router/brisk.ts b/src/router/brisk.ts index bcca858..46a5357 100644 --- a/src/router/brisk.ts +++ b/src/router/brisk.ts @@ -87,7 +87,7 @@ export class BriskRoute extends Macroable { params?: any[] | Record, options?: MakeUrlOptions & { status: number } ): Route { - return this.setHandler(async (ctx) => { + return this.setHandler(async function redirectsToRoute(ctx) { const redirector = ctx.response.redirect() if (options?.status) { redirector.status(options.status) @@ -101,7 +101,7 @@ export class BriskRoute extends Macroable { * Redirect request to a fixed URL */ redirectToPath(url: string, options?: { status: number }): Route { - return this.setHandler(async (ctx) => { + return this.setHandler(async function redirectsToPath(ctx) { const redirector = ctx.response.redirect() if (options?.status) { redirector.status(options.status) diff --git a/src/router/main.ts b/src/router/main.ts index 4619dfb..aec5e14 100644 --- a/src/router/main.ts +++ b/src/router/main.ts @@ -256,7 +256,7 @@ export class Router extends LookupStore { /** * Registers a route resource with conventional set of routes */ - resource(resource: string, controller: string) { + resource(resource: string, controller: string | LazyImport> | Constructor) { const resourceInstance = new RouteResource(this.#app, this.#middleware, { resource, controller, @@ -271,7 +271,10 @@ export class Router extends LookupStore { /** * Register a route resource with shallow nested routes. */ - shallowResource(resource: string, controller: string) { + shallowResource( + resource: string, + controller: string | LazyImport> | Constructor + ) { const resourceInstance = new RouteResource(this.#app, this.#middleware, { resource, controller, diff --git a/src/router/resource.ts b/src/router/resource.ts index 3618f35..fe32a9e 100644 --- a/src/router/resource.ts +++ b/src/router/resource.ts @@ -13,6 +13,7 @@ import { RuntimeException } from '@poppinss/utils' import type { Application } from '@adonisjs/application' import { Route } from './route.js' +import type { Constructor, LazyImport } from '../types/base.js' import type { ParsedGlobalMiddleware } from '../types/middleware.js' import type { ResourceActionNames, RouteMatcher, RouteMatchers } from '../types/route.js' @@ -29,7 +30,7 @@ export class RouteResource extends Macroable { /** * The controller to handle resource routing requests */ - #controller: string + #controller: string | LazyImport> | Constructor /** * Is it a shallow resource? Shallow resources URLs do not have parent @@ -75,7 +76,7 @@ export class RouteResource extends Macroable { routerMiddleware: ParsedGlobalMiddleware[], options: { resource: string - controller: string + controller: string | LazyImport> | Constructor globalMatchers: RouteMatchers shallow: boolean } @@ -128,7 +129,10 @@ export class RouteResource extends Macroable { const route = new Route(this.#app, this.#routerMiddleware, { pattern, methods, - handler: `${this.#controller}.${action}`, + handler: + typeof this.#controller === 'string' + ? `${this.#controller}.${action}` + : [this.#controller, action], globalMatchers: this.#globalMatchers, }) diff --git a/tests/router/resource.spec.ts b/tests/router/resource.spec.ts index 2502bc5..f794acd 100644 --- a/tests/router/resource.spec.ts +++ b/tests/router/resource.spec.ts @@ -33,7 +33,9 @@ test.group('Route Resource', () => { meta: {}, methods: ['GET', 'HEAD'], domain: 'root', - + handler: { + reference: '#controllers/photos.index', + }, name: 'photos.index', }, { @@ -42,7 +44,9 @@ test.group('Route Resource', () => { meta: {}, methods: ['GET', 'HEAD'], domain: 'root', - + handler: { + reference: '#controllers/photos.create', + }, name: 'photos.create', }, { @@ -51,6 +55,9 @@ test.group('Route Resource', () => { meta: {}, methods: ['POST'], domain: 'root', + handler: { + reference: '#controllers/photos.store', + }, name: 'photos.store', }, { @@ -59,7 +66,9 @@ test.group('Route Resource', () => { meta: {}, methods: ['GET', 'HEAD'], domain: 'root', - + handler: { + reference: '#controllers/photos.show', + }, name: 'photos.show', }, { @@ -68,7 +77,9 @@ test.group('Route Resource', () => { meta: {}, methods: ['GET', 'HEAD'], domain: 'root', - + handler: { + reference: '#controllers/photos.edit', + }, name: 'photos.edit', }, { @@ -77,7 +88,9 @@ test.group('Route Resource', () => { meta: {}, methods: ['PUT', 'PATCH'], domain: 'root', - + handler: { + reference: '#controllers/photos.update', + }, name: 'photos.update', }, { @@ -86,7 +99,9 @@ test.group('Route Resource', () => { meta: {}, methods: ['DELETE'], domain: 'root', - + handler: { + reference: '#controllers/photos.destroy', + }, name: 'photos.destroy', }, ] @@ -1169,4 +1184,198 @@ test.group('Route Resource', () => { ] ) }) + + test('define resource controller as a class reference', ({ assert }) => { + class UsersController {} + + const app = new AppFactory().create(BASE_URL, () => {}) + const resource = new RouteResource(app, [], { + resource: 'photos', + controller: UsersController, + globalMatchers: {}, + shallow: false, + }) + + assert.containsSubset( + resource.routes.map((route) => route.toJSON()), + [ + { + pattern: '/photos', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'index'], + }, + name: 'photos.index', + }, + { + pattern: '/photos/create', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'create'], + }, + name: 'photos.create', + }, + { + pattern: '/photos', + matchers: {}, + meta: {}, + methods: ['POST'], + domain: 'root', + handler: { + reference: [UsersController, 'store'], + }, + name: 'photos.store', + }, + { + pattern: '/photos/:id', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'show'], + }, + name: 'photos.show', + }, + { + pattern: '/photos/:id/edit', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'edit'], + }, + name: 'photos.edit', + }, + { + pattern: '/photos/:id', + matchers: {}, + meta: {}, + methods: ['PUT', 'PATCH'], + domain: 'root', + handler: { + reference: [UsersController, 'update'], + }, + name: 'photos.update', + }, + { + pattern: '/photos/:id', + matchers: {}, + meta: {}, + methods: ['DELETE'], + domain: 'root', + handler: { + reference: [UsersController, 'destroy'], + }, + name: 'photos.destroy', + }, + ] + ) + }) + + test('define resource controller as a lazy import reference', ({ assert }) => { + const UsersController = async () => { + return { + default: class UsersControllerClass {}, + } + } + + const app = new AppFactory().create(BASE_URL, () => {}) + const resource = new RouteResource(app, [], { + resource: 'photos', + controller: UsersController, + globalMatchers: {}, + shallow: false, + }) + + assert.containsSubset( + resource.routes.map((route) => route.toJSON()), + [ + { + pattern: '/photos', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'index'], + }, + name: 'photos.index', + }, + { + pattern: '/photos/create', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'create'], + }, + name: 'photos.create', + }, + { + pattern: '/photos', + matchers: {}, + meta: {}, + methods: ['POST'], + domain: 'root', + handler: { + reference: [UsersController, 'store'], + }, + name: 'photos.store', + }, + { + pattern: '/photos/:id', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'show'], + }, + name: 'photos.show', + }, + { + pattern: '/photos/:id/edit', + matchers: {}, + meta: {}, + methods: ['GET', 'HEAD'], + domain: 'root', + handler: { + reference: [UsersController, 'edit'], + }, + name: 'photos.edit', + }, + { + pattern: '/photos/:id', + matchers: {}, + meta: {}, + methods: ['PUT', 'PATCH'], + domain: 'root', + handler: { + reference: [UsersController, 'update'], + }, + name: 'photos.update', + }, + { + pattern: '/photos/:id', + matchers: {}, + meta: {}, + methods: ['DELETE'], + domain: 'root', + handler: { + reference: [UsersController, 'destroy'], + }, + name: 'photos.destroy', + }, + ] + ) + }) })