Skip to content

feat: implement NestJS middleware pipeline#20

Merged
VikramAditya33 merged 1 commit into
v2-http-supportfrom
v2-p5
Apr 21, 2026
Merged

feat: implement NestJS middleware pipeline#20
VikramAditya33 merged 1 commit into
v2-http-supportfrom
v2-p5

Conversation

@VikramAditya33
Copy link
Copy Markdown
Collaborator

@VikramAditya33 VikramAditya33 commented Apr 20, 2026

Implements complete NestJS middleware support for the uWS platform adapter.

What's Implemented

Core Middleware Components

  • Guards: Authorization and access control with execution order support
  • Pipes: Data transformation and validation pipeline
  • Exception Filters: Error handling with filter chaining
  • Interceptors: Request/response transformation (placeholder for future)

Execution Context

  • HttpExecutionContext: NestJS execution context implementation
  • Context switching: switchToHttp(), switchToRpc(), switchToWs()
  • Argument access: getArgs(), getArgByIndex(), getClass(), getHandler()

Route Registry Enhancements

  • Middleware metadata storage per route
  • Execution pipeline: Guards → Pipes → Handler → Filters
  • Short-circuit on guard failure
  • Error propagation through filter chain

Test Coverage

  • 604 total tests passing
  • Guards integration tests (4 tests)
  • Pipes integration tests (2 tests)
  • Exception filters tests (4 tests)
  • Full pipeline tests (2 tests)
  • HTTP context tests (21 tests)
  • Metadata storage tests (2 tests)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added custom logger support for HTTP operations (defaults to console logging)
    • Implemented middleware pipeline for HTTP routes, including guards, pipes, and exception filters
    • Enhanced execution context for HTTP requests with improved metadata handling
    • Request body transformation via pipes for request processing
  • Improvements

    • Better error handling with support for exception filters and status codes
    • Improved request/response context switching for framework integration

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e0969b06-e1dc-47e7-845a-e2ab21ad9b06

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v2-p5

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/platform/route-registry-middleware.spec.ts`:
- Around line 179-199: The test registers an UpperCasePipe but never supplies a
request body, so the handler awaits req.body and the pipe never receives
"hello"; fix by feeding the mocked uWS request with the raw body before invoking
the registered handler: simulate the request body delivery on mockUwsReq (e.g.,
resolve its body promise or call the mock onData/onEnd/data callback with the
string "hello") so that when registry.register('POST','/test', handler, { pipes:
[UpperCasePipe] }) is executed and you call
registeredRoutes.get('POST:/test')?.handler!(mockUwsRes, mockUwsReq), the pipe
will receive "hello" and the handler will assert "HELLO". Ensure you use the
same mock hooks your body-parsing code relies on (mockUwsReq.body,
mockUwsReq.onData, mockUwsReq.onEnd, or mockUwsReq.forEach) so the
UpperCasePipe.transform is exercised.

In `@src/platform/route-registry.ts`:
- Around line 506-512: The default error path always sends a 500, losing
original HTTP status when an HttpException (e.g., BadRequestException,
UnauthorizedException) was thrown; update the error branch that currently calls
res.status(500).send(...) to preserve the exception status and response body:
detect if the thrown error is an instance of HttpException (or has
getStatus/getResponse methods), and if so call
res.status(err.getStatus()).send(err.getResponse() || { statusCode:
err.getStatus(), message: err.message }); otherwise keep the generic 500
payload; reference symbols: HttpException, BadRequestException,
UnauthorizedException, res.headersSent, res.status(...).send(...).
- Around line 426-430: The code currently calls pipe.transform with type/body
metadata hardcoded to undefined, preventing Nest pipes from validating; update
the RouteMetadata interface to include an optional bodyMetadata?:
ArgumentMetadata, change executePipes(route: RouteMetadata, ...) (and its
callers) to accept and forward that ArgumentMetadata, and replace the hardcoded
object passed to pipe.transform in executePipes with the provided bodyMetadata
(e.g., { type: 'body', ...route.bodyMetadata }) so pipes like ValidationPipe
receive the real metatype and data; ensure callers that register routes can
optionally supply the new bodyMetadata field.
- Around line 393-397: Guards and pipes may return Observables, but the current
await on guard.canActivate and pipe.transform will treat Observable objects as
truthy; update the execution in the RouteRegistry where guard.canActivate
(referenced as guard.canActivate(context as ExecutionContext)) and
pipe.transform (referenced as pipe.transform(value, metadata, { type:
'transform' })) are called to detect Observable results using isObservable(...)
and, if true, resolve them with lastValueFrom(...) before using the result;
ensure the resolved guard value is coerced to boolean before gating execution
and the resolved pipe value replaces the request body/value.
- Around line 388-391: The loop currently instantiates guards/pipes/filters
directly (e.g., new GuardType(), new PipeType(), new FilterType()), which
bypasses DI; change those instantiations to resolve instances from the Nest
moduleRef by calling this.options.moduleRef.get(GuardType) (and similarly for
PipeType and FilterType) so constructor-injected dependencies are provided;
ensure you follow the same resolution pattern used in GuardExecutor,
PipeExecutor, and ExceptionFilterExecutor and handle null/undefined returns the
same way the other executors do.

In `@src/platform/test-helpers.ts`:
- Around line 1-4: The test helper module test-helpers.ts (imports HttpRequest,
HttpResponse and uWS) is being compiled into production artifacts; either rename
the file to match test patterns (e.g., test-helpers.test.ts) or move it into an
explicitly excluded test directory (e.g., a testing folder), then update
tsconfig.build.json to add that directory (e.g., "src/testing") to the "exclude"
array so the compiler skips it; also verify package.json "files" doesn't include
the helper so it won't be packaged for consumers.

In `@src/platform/uws-platform.adapter.ts`:
- Around line 577-612: The current numeric-to-string mapping in methodMap
silently defaults unknown numeric RequestMethod values to 'GET', which can
mis-register WebDAV or unsupported verbs; update the logic around requestMethod
and methodMap so that when requestMethod is a number you validate it against an
explicit supportedMethods set (e.g.,
['GET','POST','PUT','DELETE','PATCH','OPTIONS','HEAD','ALL']) before calling
routeRegistry.register, and throw an explicit error for any numeric enum value
not in that set (include requestMethod value in the error). Also validate string
requestMethod by uppercasing it (as done) and rejecting any resulting verb not
present in the same supportedMethods set, throwing a clear error instead of
silently mapping to GET; keep references to methodMap, requestMethod, method,
and routeRegistry.register to locate the code to change.

In `@src/platform/uws-request.ts`:
- Around line 76-77: The class currently uses the optional property
transformedBody?: unknown to both store a transformed value and indicate
presence, which treats a legitimate transformed undefined as "not set" and
triggers fallback parsing; add a separate boolean flag (e.g., transformedBodySet
or hasTransformedBody) initialized false, update the setter (where
transformedBody is assigned) to also set that flag to true even when the
assigned value is undefined, and change all reads (the body getter and any
checks) to test the flag instead of checking transformedBody !== undefined;
apply the same change for the other occurrences referenced by the reviewer
(around the methods/properties named transformedBody, any setTransformedBody or
body getter logic at the other locations).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8579b853-dac1-410c-ad4a-6f6b6859884b

📥 Commits

Reviewing files that changed from the base of the PR and between 31b3cdd and b75327a.

📒 Files selected for processing (11)
  • src/interfaces/http-options.interface.ts
  • src/platform/http-context.spec.ts
  • src/platform/http-context.ts
  • src/platform/index.ts
  • src/platform/route-registry-middleware.spec.ts
  • src/platform/route-registry.spec.ts
  • src/platform/route-registry.ts
  • src/platform/test-helpers.ts
  • src/platform/uws-platform.adapter.spec.ts
  • src/platform/uws-platform.adapter.ts
  • src/platform/uws-request.ts

Comment thread src/platform/route-registry-middleware.spec.ts
Comment thread src/platform/route-registry.ts Outdated
Comment thread src/platform/route-registry.ts
Comment thread src/platform/route-registry.ts Outdated
Comment thread src/platform/route-registry.ts Outdated
Comment thread src/platform/test-helpers.ts
Comment thread src/platform/uws-platform.adapter.ts
Comment thread src/platform/uws-request.ts
@VikramAditya33 VikramAditya33 force-pushed the v2-p5 branch 3 times, most recently from 011722a to e4b15a6 Compare April 21, 2026 07:33
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
src/platform/test-helpers.ts (4)

224-226: listen mock ignores the 2-arg overload and always invokes the callback.

uWS.TemplatedApp.listen has multiple overloads — (port, cb), (host, port, cb), and (port, options, cb). The mock hard-codes the 3-arg shape, so any production code path calling app.listen(port, cb) against this mock will pass the callback as _port and silently do nothing. If uws-platform.adapter.ts only ever uses the 3-arg form this is fine, but it's a latent footgun. Consider using a variadic signature that picks the last arg as the callback.

-    listen: jest.fn((_host: string, _port: number, callback: (socket: unknown) => void) => {
-      callback(listenSocket);
-    }),
+    listen: jest.fn((...args: unknown[]) => {
+      const callback = args[args.length - 1] as (socket: unknown) => void;
+      if (typeof callback === 'function') callback(listenSocket);
+    }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/test-helpers.ts` around lines 224 - 226, The listen mock in
src/platform/test-helpers.ts currently assumes a 3-arg signature and always
calls the callback, which breaks the 2-arg overload used by
uWS.TemplatedApp.listen; change the jest.fn for listen to accept variadic args
(e.g., ...args), detect the last argument as the callback if it's a function,
and invoke it with listenSocket, otherwise return a failure indicator; update
references to listenSocket and ensure this mock covers the (port, cb), (host,
port, cb), and (port, options, cb) forms so uws-platform.adapter.ts tests behave
like production.

196-242: trackRoutes defaults to true, which contradicts the opt-in framing in the JSDoc example.

The example at line 190 passes { trackRoutes: true } explicitly, implying opt-in, but the default is already true. Either flip the default to false (opt-in, matching the example) or drop the explicit flag from the example to avoid confusion for readers. Also, registeredRoutes is always returned even when tracking is disabled — fine, just noting for clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/test-helpers.ts` around lines 196 - 242, The default behavior of
createMockUwsApp currently sets trackRoutes to true which conflicts with the
JSDoc/example that treats route tracking as opt-in; change the default in the
createMockUwsApp options destructuring to trackRoutes = false (or alternatively
remove the explicit { trackRoutes: true } in the example), ensuring the
MockUwsAppOptions default aligns with the JSDoc, and leave registeredRoutes
returned (it can remain empty when tracking is disabled).

151-151: tryEnd mock ignores writeSuccess option.

write is wired to writeSuccess, but tryEnd always returns [true, false] regardless. Tests that exercise backpressure through tryEnd have to override it manually (as uws-response.spec.ts does at line 969, 981, 1012). For consistency, consider having tryEnd honor writeSuccess as the ok flag, e.g. [writeSuccess, false].

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/test-helpers.ts` at line 151, The tryEnd mock currently always
returns [true, false] which ignores the writeSuccess flag used by the write
mock; update the jest.fn for tryEnd in test-helpers so it returns [writeSuccess,
false] (i.e., use the same writeSuccess boolean that the write mock reads) so
backpressure behavior is consistent with the write mock and existing tests like
uws-response.spec.ts no longer need to override tryEnd manually.

78-79: Falsy-coalescing may mask legitimate empty/zero parameter or header values.

params[index] || '' and headers[name.toLowerCase()] || '' behave fine today because all values are strings, but if a test ever sets a parameter to '0' or '' intentionally, the || fallback still yields '' — which is what real uWS also returns for missing values, so it's indistinguishable. Consider params[index] ?? '' to at least preserve nullish semantics clearly. Low priority.

-    getParameter: jest.fn((index: number) => params[index] || ''),
-    getHeader: jest.fn((name: string) => headers[name.toLowerCase()] || ''),
+    getParameter: jest.fn((index: number) => params[index] ?? ''),
+    getHeader: jest.fn((name: string) => headers[name.toLowerCase()] ?? ''),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/test-helpers.ts` around lines 78 - 79, The mock implementations
for getParameter and getHeader use falsy-coalescing which masks legitimate empty
or "0" values; update the jest.fn callbacks for getParameter (referencing params
and index) and getHeader (referencing headers and name.toLowerCase()) to use
nullish coalescing (?? '') instead of || '' so that non-null/defined falsy
strings like '0' or '' are preserved while still defaulting to '' for
undefined/null missing values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/platform/test-helpers.ts`:
- Around line 131-144: The mock response's onAborted currently invokes the abort
callback synchronously when aborted is true, causing UwsResponse constructor
(and tests) to observe a synchronous abort; update mockRes.onAborted so it
stores callbacks.onAborted = callback but defers invocation (e.g., via
queueMicrotask or setImmediate) when aborted is true, or alternatively remove
automatic invocation and document that tests should call callbacks.onAborted!()
after constructing UwsResponse; change references in tests that rely on
synchronous behavior to explicitly invoke callbacks.onAborted instead of passing
aborted: true.

---

Nitpick comments:
In `@src/platform/test-helpers.ts`:
- Around line 224-226: The listen mock in src/platform/test-helpers.ts currently
assumes a 3-arg signature and always calls the callback, which breaks the 2-arg
overload used by uWS.TemplatedApp.listen; change the jest.fn for listen to
accept variadic args (e.g., ...args), detect the last argument as the callback
if it's a function, and invoke it with listenSocket, otherwise return a failure
indicator; update references to listenSocket and ensure this mock covers the
(port, cb), (host, port, cb), and (port, options, cb) forms so
uws-platform.adapter.ts tests behave like production.
- Around line 196-242: The default behavior of createMockUwsApp currently sets
trackRoutes to true which conflicts with the JSDoc/example that treats route
tracking as opt-in; change the default in the createMockUwsApp options
destructuring to trackRoutes = false (or alternatively remove the explicit {
trackRoutes: true } in the example), ensuring the MockUwsAppOptions default
aligns with the JSDoc, and leave registeredRoutes returned (it can remain empty
when tracking is disabled).
- Line 151: The tryEnd mock currently always returns [true, false] which ignores
the writeSuccess flag used by the write mock; update the jest.fn for tryEnd in
test-helpers so it returns [writeSuccess, false] (i.e., use the same
writeSuccess boolean that the write mock reads) so backpressure behavior is
consistent with the write mock and existing tests like uws-response.spec.ts no
longer need to override tryEnd manually.
- Around line 78-79: The mock implementations for getParameter and getHeader use
falsy-coalescing which masks legitimate empty or "0" values; update the jest.fn
callbacks for getParameter (referencing params and index) and getHeader
(referencing headers and name.toLowerCase()) to use nullish coalescing (?? '')
instead of || '' so that non-null/defined falsy strings like '0' or '' are
preserved while still defaulting to '' for undefined/null missing values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a2ee2442-3e7b-41b9-bae7-85eb2869f64b

📥 Commits

Reviewing files that changed from the base of the PR and between b75327a and e4b15a6.

📒 Files selected for processing (15)
  • package.json
  • src/index.ts
  • src/interfaces/http-options.interface.ts
  • src/platform/http-context.spec.ts
  • src/platform/http-context.ts
  • src/platform/index.ts
  • src/platform/route-registry-middleware.spec.ts
  • src/platform/route-registry.spec.ts
  • src/platform/route-registry.ts
  • src/platform/test-helpers.ts
  • src/platform/uws-platform.adapter.spec.ts
  • src/platform/uws-platform.adapter.ts
  • src/platform/uws-request.ts
  • src/platform/uws-response.spec.ts
  • tsconfig.build.json
✅ Files skipped from review due to trivial changes (4)
  • tsconfig.build.json
  • package.json
  • src/platform/route-registry-middleware.spec.ts
  • src/platform/http-context.spec.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/platform/uws-platform.adapter.spec.ts
  • src/platform/index.ts
  • src/platform/uws-request.ts
  • src/interfaces/http-options.interface.ts
  • src/platform/http-context.ts
  • src/platform/uws-platform.adapter.ts
  • src/platform/route-registry.ts
  • src/platform/route-registry.spec.ts

Comment thread src/platform/test-helpers.ts
Implement complete NestJS middleware integration with guards, pipes,
exception filters, and interceptors. Add HTTP execution context and
comprehensive test coverage.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant