You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(nest): apply method-level decorators to router-contract @Implement routes (#1776)
Method-level NestJS enhancers (`@UseGuards`, `@UsePipes`, `@UseFilters`,
`@SetMetadata`, ...) on a router-contract `@Implement` method never
reached the synthesized route handlers — guards silently never ran,
leaving those routes unprotected regardless of decorator order. Enhancer
metadata now reaches every synthesized route, decorator placement around
`@Implement` no longer matters for whether enhancers apply, and
interceptor execution order follows decorator order exactly like on
plain NestJS methods.
## Fixes
- Synthesized methods inherit from the original method via the prototype
chain, so guards, pipes, filters, and `@SetMetadata` resolve through
NestJS's `Reflect.getMetadata` lookups and now run on every route,
including nested routers.
- `ImplementInterceptor` is registered at the decorated method level, so
the interceptor list carries user interceptors and
`ImplementInterceptor` in native decorator-evaluation order:
interceptors below `@Implement` observe the encoded response,
interceptors above it run inside and observe the raw implemented
procedure — identical between single-procedure and router-contract
implementations.
- The router branch no longer recurses through `Implement` itself:
routing and status decorators are applied directly to synthesized
methods, deferred (with the method-name-keyed metadata copies) until the
whole decorator stack has run, so late-running decorators are picked up
and route metadata is always written last.
- The documented ordering restriction is gone; the docs warning is
replaced with a note that decorators combine with `@Implement` in any
order and that execution order follows decorator order.
## Testing
- Header-based `AuthGuard` e2e test: requests without the token are
rejected (403) and with it succeed (200) on all synthesized routes
including a nested procedure, in both decorator orders. Before the fix
the guard never executed.
- Interceptor-order e2e tests for both single-procedure and
router-contract `@Implement`, in both decorator orders, asserting what
the user interceptor observes (encoded response vs raw procedure).
- The conflict-method-names test boots a real app: routes serve
correctly, `@Req()` injection works on synthesized methods, and
`@SetMetadata` from both sides of `@Implement` is visible via
`Reflector` on `ctx.getHandler()` at runtime.
Copy file name to clipboardExpand all lines: apps/content/docs/integrations/nest.md
+2-16Lines changed: 2 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -103,22 +103,8 @@ export class PlanetController {
103
103
}
104
104
```
105
105
106
-
::: warning
107
-
If you using `@Implement` decorator for router contract, underhook it creates corresponding NestJS method for each procedure contract. Therefore, all other decorator should be applied before `@Implement` decorator, otherwise it will not be applied to corresponding NestJS methods.
108
-
109
-
```ts
110
-
@Controller()
111
-
exportclassPlanetController {
112
-
@Implement(contract.planet) // ⬇️ other decorators should be below this line
113
-
@UseGuards(AuthGuard)
114
-
planet(@Req() req:Request) {
115
-
return {
116
-
// your implementation
117
-
}
118
-
}
119
-
}
120
-
```
121
-
106
+
::: info
107
+
When you use the `@Implement` decorator with a router contract, under the hood it creates a corresponding NestJS method for each procedure contract. All decorators applied to the original method are reflected on these methods.
it('router-based implementation controller can handle conflict method names and reflect all metadata on new methods',async()=>{
845
+
it('router-based implementation controller can handle conflict method names and reflect all metadata on new methods regardless of decorator order',async()=>{
0 commit comments