Add Feature expansion .use(path, middleware)#3044
Add Feature expansion .use(path, middleware)#3044Octo8080X wants to merge 16 commits intodenoland:mainfrom
Conversation
src/router.ts
Outdated
| export interface Route<T> { | ||
| path: string | URLPattern; | ||
| method: Method | "ALL"; | ||
| method: Method | "ALL" | "MIDDLEWARE"; |
There was a problem hiding this comment.
This seems odd to me. Is there an alternative?
There was a problem hiding this comment.
I think there’s a way to use “ALL” instead of “MIDDLEWARE”.
Or we could allow undefined, but I feel that would have too large of an impact.
There was a problem hiding this comment.
I decided to go with "ALL".
src/app.ts
Outdated
| const middlewareHandlers: Array<MiddlewareFn<State>> = []; | ||
| for (const middleware of middlewares) { | ||
| for (const handler of middleware.handlers) { | ||
| // We need to safely cast here to handle the type properly | ||
| middlewareHandlers.push(handler as unknown as MiddlewareFn<State>); | ||
| } | ||
| } |
There was a problem hiding this comment.
| const middlewareHandlers: Array<MiddlewareFn<State>> = []; | |
| for (const middleware of middlewares) { | |
| for (const handler of middleware.handlers) { | |
| // We need to safely cast here to handle the type properly | |
| middlewareHandlers.push(handler as unknown as MiddlewareFn<State>); | |
| } | |
| } | |
| const middlewareHandlers = middlewares.flatMap((middleware) => | |
| middleware.handlers | |
| ); |
| // Create a new array of handlers with the correct type | ||
| const combinedHandlers: Array<MiddlewareFn<State>> = [ | ||
| ...middlewareHandlers, | ||
| ...route.handlers.map((h) => h as unknown as MiddlewareFn<State>), | ||
| ]; |
There was a problem hiding this comment.
| // Create a new array of handlers with the correct type | |
| const combinedHandlers: Array<MiddlewareFn<State>> = [ | |
| ...middlewareHandlers, | |
| ...route.handlers.map((h) => h as unknown as MiddlewareFn<State>), | |
| ]; | |
| const combinedHandlers = [ | |
| ...middlewareHandlers, | |
| ...route.handlers, | |
| ]; |
src/app.ts
Outdated
| if ( | ||
| typeof pathOrMiddleware === "string" || | ||
| pathOrMiddleware instanceof URLPattern | ||
| ) { | ||
| // First argument is a path | ||
| if (!middleware) { | ||
| throw new Error("Middleware is required when path is provided"); | ||
| } | ||
| this.#router.addMiddleware(pathOrMiddleware, middleware); | ||
| } else { | ||
| this.#router.addMiddleware("/*", pathOrMiddleware); | ||
| } |
There was a problem hiding this comment.
| if ( | |
| typeof pathOrMiddleware === "string" || | |
| pathOrMiddleware instanceof URLPattern | |
| ) { | |
| // First argument is a path | |
| if (!middleware) { | |
| throw new Error("Middleware is required when path is provided"); | |
| } | |
| this.#router.addMiddleware(pathOrMiddleware, middleware); | |
| } else { | |
| this.#router.addMiddleware("/*", pathOrMiddleware); | |
| } | |
| if (typeof pathOrMiddleware === "function") { | |
| this.#router.addMiddleware("/*", pathOrMiddleware); | |
| return this; | |
| } | |
| if (!middleware) { | |
| throw new TypeError("Middleware is required when path is provided"); | |
| } | |
| this.#router.addMiddleware(pathOrMiddleware, middleware); |
Maybe a little tidier?
There was a problem hiding this comment.
Thank you.
With the suggested approach, pathOrMiddleware can't be narrowed down to string | URLPattern, which causes a type error—so I decided to keep it as it is for now.
src/router.ts
Outdated
| if ( | ||
| typeof pathname === "string" && pathname !== "/*" && | ||
| IS_PATTERN.test(pathname) | ||
| ) { | ||
| this._middlewares.push({ | ||
| path: new URLPattern({ pathname }), | ||
| handlers: [handler], | ||
| method: "MIDDLEWARE", | ||
| }); | ||
| } else { | ||
| this._middlewares.push({ | ||
| path: pathname, | ||
| handlers: [handler], | ||
| method: "MIDDLEWARE", | ||
| }); | ||
| } |
There was a problem hiding this comment.
| if ( | |
| typeof pathname === "string" && pathname !== "/*" && | |
| IS_PATTERN.test(pathname) | |
| ) { | |
| this._middlewares.push({ | |
| path: new URLPattern({ pathname }), | |
| handlers: [handler], | |
| method: "MIDDLEWARE", | |
| }); | |
| } else { | |
| this._middlewares.push({ | |
| path: pathname, | |
| handlers: [handler], | |
| method: "MIDDLEWARE", | |
| }); | |
| } | |
| this._middlewares.push({ | |
| path: isPattern(pathname) ? new URLPattern({ pathname }) : pathname, | |
| handlers: [handler], | |
| method: "MIDDLEWARE", | |
| }); |
We can factor out that conditional into an isPattern() which can be reused on lines 60-61.
There was a problem hiding this comment.
Thanks!
I extracted it as isURLPattern.
src/router.ts
Outdated
| path: ( | ||
| typeof pathname === "string" && pathname !== "/*" && | ||
| !this.isURLPattern(pathname) | ||
| ) |
There was a problem hiding this comment.
Nit: To clarify, my idea was to have everything inside this condition be factored out. Not just the URLPattern bit. Also, I don't see a reason why it should be a method when it doesn't use any property from this class.
There was a problem hiding this comment.
Apologies — I didn’t fully grasp your intent at first.
I’ve now moved the logic out of the class and reorganized the content.
…0X/fresh into feature/add_middleware_with_path
iuioiua
left a comment
There was a problem hiding this comment.
LGTM! Just a few non-blocking nits.
src/app.ts
Outdated
| this.#router.addMiddleware("/*", pathOrMiddleware); | ||
| } else { | ||
| if (!middleware) { | ||
| throw new Error("Middleware is required when path is provided"); |
There was a problem hiding this comment.
| throw new Error("Middleware is required when path is provided"); | |
| throw new TypeError("Middleware is required when path is provided"); |
Nit
src/app.ts
Outdated
| : middlewares.concat(route.handlers); | ||
| this.#router.add(route.method, merged, combined); | ||
| // Create a new array of handlers with the correct type | ||
| const combinedHandlers: Array<MiddlewareFn<State>> = [ |
There was a problem hiding this comment.
| const combinedHandlers: Array<MiddlewareFn<State>> = [ | |
| const combinedHandlers = [ |
Nit: this might not be needed
src/router.ts
Outdated
| method: Method | "ALL", | ||
| pathname: string | URLPattern, | ||
| handlers: T[], | ||
| ): void { |
There was a problem hiding this comment.
| ): void { | |
| ) { |
Nit: the Deno team consider defining void and Promise<void> as explicit return types as needless boilerplate.
|
Thanks for working on a PR. We've refactored the internals of Fresh quite a bite to have sort of an internal route tree when building up the middlewares. This was needed to get other features in that we needed, but does unfortunately mean that the functionality proposed in this PR has already been implemented, see #3086 |
target: #3040
Currently in progress.