Skip to content

Commit 56695f3

Browse files
authored
feat(nest): custom send response, global context, plugins, custom error response (#1256)
- [x] custom send response - [x] global context - [x] plugins - [ ] ~~error filter~~ - [x] custom error response - [x] tests - [x] docs <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Custom response interceptors for overriding response body and headers * Dynamic per-route success status support * Async module configuration that injects the request into handler context * Configurable JSON/serializer options and plugin support * **Documentation** * Updated Nest integration guide with an advanced "Custom Send Response" example * **Tests** * Expanded tests for dynamic statuses, interceptors, serializers, and compatibility scenarios <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 1fe4418 commit 56695f3

File tree

9 files changed

+511
-156
lines changed

9 files changed

+511
-156
lines changed

apps/content/docs/openapi/integrations/implement-contract-in-nest.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,23 @@ oRPC will use NestJS parsed body when it's available, and only use the oRPC pars
220220
Configure the `@orpc/nest` module by importing `ORPCModule` in your NestJS application:
221221

222222
```ts
223+
import { Module } from '@nestjs/common'
223224
import { REQUEST } from '@nestjs/core'
224225
import { onError, ORPCModule } from '@orpc/nest'
225226
import { Request } from 'express' // if you use express adapter
226227
228+
declare module '@orpc/nest' {
229+
/**
230+
* Extend oRPC global context to make it type-safe inside your handlers/middlewares
231+
*/
232+
interface ORPCGlobalContext {
233+
request: Request
234+
}
235+
}
236+
227237
@Module({
228238
imports: [
229-
ORPCModule.forRootAsync({ // or .forRoot
239+
ORPCModule.forRootAsync({ // or use .forRoot for static config
230240
useFactory: (request: Request) => ({
231241
interceptors: [
232242
onError((error) => {
@@ -235,6 +245,8 @@ import { Request } from 'express' // if you use express adapter
235245
],
236246
context: { request }, // oRPC context, accessible from middlewares, etc.
237247
eventIteratorKeepAliveInterval: 5000, // 5 seconds
248+
customJsonSerializers: [],
249+
plugins: [], // most oRPC plugins are compatible
238250
}),
239251
inject: [REQUEST],
240252
}),
@@ -274,3 +286,47 @@ const client: JsonifiedClient<ContractRouterClient<typeof contract>> = createORP
274286
::: info
275287
Please refer to the [OpenAPILink](/docs/openapi/client/openapi-link) documentation for more information on client setup and options.
276288
:::
289+
290+
## Advanced
291+
292+
### Custom Send Response
293+
294+
By default, oRPC sends the response directly without returning it to the NestJS handler. However, you may want to preserve the return behavior for compatibility with certain NestJS features or third-party libraries.
295+
296+
```ts
297+
import { Module } from '@nestjs/common'
298+
import { ORPCModule } from '@orpc/nest'
299+
import { Response } from 'express' // if you use express adapter
300+
import { isObject } from '@orpc/shared' // checks if value is a plain object (not a class instance)
301+
302+
@Module({
303+
imports: [
304+
ORPCModule.forRoot({
305+
sendResponseInterceptors: [
306+
async ({ response, standardResponse, next }) => {
307+
if (
308+
standardResponse.status < 200
309+
|| standardResponse.status >= 300
310+
|| !(isObject(standardResponse.body) || Array.isArray(standardResponse.body))
311+
) {
312+
// Only object and array are valid to return as response body
313+
// the rest should fallback to default oRPC behavior
314+
return next()
315+
}
316+
317+
const expressResponse = response as Response
318+
expressResponse.status(standardResponse.status)
319+
for (const [key, value] of Object.entries(standardResponse.headers)) {
320+
if (value !== undefined) {
321+
expressResponse.setHeader(key, value)
322+
}
323+
}
324+
325+
return standardResponse.body
326+
},
327+
],
328+
}),
329+
],
330+
})
331+
export class AppModule {}
332+
```

0 commit comments

Comments
 (0)