@@ -85,6 +85,7 @@ export interface RouteInfo {
8585 handler : RouteHandler ; // Store the handler
8686 metadata ?: RouteMetadata ; // Middleware metadata
8787 implicitHead ?: boolean ; // Auto-registered HEAD fallback for GET routes
88+ trailingSlash ?: boolean ; // Auto-registered trailing-slash variant for Express compatibility
8889}
8990
9091/**
@@ -252,6 +253,11 @@ export class RouteRegistry {
252253 } ;
253254
254255 this . routes . set ( routeKey , routeInfo ) ;
256+ // Also update trailing-slash variant if it exists
257+ const slashRouteKey = `${ normalizedMethod } :${ path } /` ;
258+ if ( this . routes . has ( slashRouteKey ) ) {
259+ this . routes . set ( slashRouteKey , { ...routeInfo , trailingSlash : true } ) ;
260+ }
255261 if ( isComplex ) {
256262 const staticPrefix = this . extractStaticPrefix ( path ) ;
257263 const registrationPath = staticPrefix ? `${ staticPrefix } /*` : '/*' ;
@@ -385,11 +391,9 @@ export class RouteRegistry {
385391 this . complexRoutesByWildcard . get ( wildcardKey ) ! . push ( routeInfo ) ;
386392 } else {
387393 // Simple route - use native uWS routing
388- uwsMethodFn . call (
389- this . uwsApp ,
390- uwsPath ,
391- async ( uwsRes : uWS . HttpResponse , uwsReq : uWS . HttpRequest ) => {
392- const activeRoute = this . routes . get ( routeKey ) ! ;
394+ const createHandler =
395+ ( key : string ) => async ( uwsRes : uWS . HttpResponse , uwsReq : uWS . HttpRequest ) => {
396+ const activeRoute = this . routes . get ( key ) ! ;
393397
394398 // Create request/response wrappers
395399 const req = new UwsRequest ( uwsReq , uwsRes , paramNames ) ;
@@ -414,8 +418,19 @@ export class RouteRegistry {
414418
415419 // Execute handler with error handling
416420 await this . executeHandler ( activeRoute . handler , req , res , activeRoute . metadata ) ;
421+ } ;
422+
423+ uwsMethodFn . call ( this . uwsApp , uwsPath , createHandler ( routeKey ) ) ;
424+
425+ // Also register trailing-slash variant for Express compatibility
426+ // (e.g. /api and /api/ should both match the same route)
427+ if ( ! uwsPath . endsWith ( '/' ) && uwsPath !== '/' ) {
428+ const slashRouteKey = `${ normalizedMethod } :${ path } /` ;
429+ if ( ! this . routes . has ( slashRouteKey ) ) {
430+ this . routes . set ( slashRouteKey , { ...routeInfo , trailingSlash : true } ) ;
431+ uwsMethodFn . call ( this . uwsApp , uwsPath + '/' , createHandler ( slashRouteKey ) ) ;
417432 }
418- ) ;
433+ }
419434 }
420435
421436 if ( normalizedMethod === 'GET' && ! implicitHead ) {
@@ -935,7 +950,9 @@ export class RouteRegistry {
935950 * @returns Map of route keys to route information
936951 */
937952 getRoutes ( ) : Map < string , RouteInfo > {
938- return new Map ( [ ...this . routes ] . filter ( ( [ , route ] ) => ! route . implicitHead ) ) ;
953+ return new Map (
954+ [ ...this . routes ] . filter ( ( [ , route ] ) => ! route . implicitHead && ! route . trailingSlash )
955+ ) ;
939956 }
940957
941958 /**
@@ -957,7 +974,8 @@ export class RouteRegistry {
957974 * @returns Number of registered routes
958975 */
959976 getRouteCount ( ) : number {
960- return [ ...this . routes . values ( ) ] . filter ( ( route ) => ! route . implicitHead ) . length ;
977+ return [ ...this . routes . values ( ) ] . filter ( ( route ) => ! route . implicitHead && ! route . trailingSlash )
978+ . length ;
961979 }
962980
963981 private replaceComplexRoute ( wildcardKey : string , routeInfo : RouteInfo ) : void {
0 commit comments