Skip to content

Conversation

@Mathiasduc
Copy link

This PR all the tested features of Nest to integrate better with orpc and it's feature.
For example:

  1. global interceptors can now modify the Orpc response.
  2. method interceptors declared after @implement can modify the response.
  3. guards that, for example, write on the req object will now be able to access the req and res object in the handler context. (was already possible with the context config if I understood this correctly? )
  4. Filter and especially Exception filters can now choose to catch the ORPC errors or declare the newly provided ORPCExceptionFilter to keep the same behaviour.

Basically everything that was trying to modify the response after the handler was failing due to the handler sending the response.
The handler now set headers, status code, return the proper body and let the middleware chain resolve and let Nest/Node send the response at the end.

@vercel
Copy link

vercel bot commented Oct 29, 2025

@Mathiasduc is attempting to deploy a commit to the unnoq-team Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

Important

Review skipped

Draft detected.

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.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@Mathiasduc
Copy link
Author

Mathiasduc commented Oct 29, 2025

Hi @unnoq This is the PR we were talking about in #992 .
It is , I feel like, a big departure from the previous implementation and other integrations but I think it is the most standard and future proof implementation of this integration.
It will allow teams, like us, to better migrate to Orpc from an existing Nest app.
Current implementation breaks a lot of feature that most Nest app probably use.
This is in draft because I'm not satisfied with the testing.
It lacks testing for the new 'standard' functions and more in depth testing for mixing Nest and Orpc feature.
But I'm curious if that approach is ok with you and if I can keep iterating and keep at polishing it.

@Mathiasduc Mathiasduc force-pushed the feat/server/nest/add-support-for-nestjs-features branch from 6892585 to 8366106 Compare October 29, 2025 12:11
Copy link
Owner

@unnoq unnoq left a comment

Choose a reason for hiding this comment

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

I still don’t understand why we need to use return just to increase compatibility with NestJS. Modifying the response body is an anti-pattern and makes it incompatible with the generated openapi spec. Why not modify the headers instead? We can already change headers without requiring a return.


const client = createProcedureClient(procedure, {
...this.config,
context: contextWithRequest,
Copy link
Owner

@unnoq unnoq Oct 29, 2025

Choose a reason for hiding this comment

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

This approach is not typesafe. While implement expects an empty context {}, this can lead to problems. For instance, a middleware might expect a context like { request?: number | undefined }. Because an empty object {} doesn't conflict can satisfy middleware's dependent-context so we can .use when implement. But in this case request is req -> middleware can run failed because middleware expect request is undefined or number

* @param headers - WARNING: The headers can be mutated by the function and may affect the original headers.
* @param options
*/
export function toResponseBody(
Copy link
Owner

Choose a reason for hiding this comment

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

I don't think this package needs these APIs. I believe we should write it inside the nest package instead. We can implement some of them as signal functions

Copy link
Author

Choose a reason for hiding this comment

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

I'll try to not need to define this function since it's so similar to toNodeHttpBody. Adding an option to stringify the body or not should be enough.

We can implement some of them as signal functions

I did not understand what you meant by that.

Copy link
Owner

Choose a reason for hiding this comment

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

I mean you can write a signal function in nest package instead.

import * as StandardServerFastify from '@orpc/standard-server-fastify'
import * as StandardServerNode from '@orpc/standard-server-node'

const codec = new StandardOpenAPICodec(
Copy link
Owner

Choose a reason for hiding this comment

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

I'm looking for a way to make all codecs extendable. Specifically, I'd like to know if it's possible to add a custom serializer by passing it into the main configuration, similar to the method described for extending native data types.

// Set status and headers
if ('raw' in res) {
await StandardServerFastify.sendStandardResponse(res, standardResponse, this.config)
return StandardServerFastify.setStandardResponse(res as FastifyReply, standardResponse, this.config)
Copy link
Owner

Choose a reason for hiding this comment

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

Make sure you tests there cases:

  • undefined in this case expect body is empty + no content-type is set
  • json data in this case expect return json data (not stringify) + content-type is json
  • file/blob in this case expect streaming response + content-type = file.type

@Mathiasduc Mathiasduc changed the title feat(server): Change the nest integration to support Nest features that were competing with Orpc feat(nest): Change the nest integration to support Nest features that were competing with Orpc Oct 29, 2025
@codecov
Copy link

codecov bot commented Oct 29, 2025

Codecov Report

❌ Patch coverage is 81.52866% with 29 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/standard-server-node/src/body.ts 69.44% 11 Missing ⚠️
packages/nest/src/implement.ts 78.94% 8 Missing ⚠️
packages/standard-server-node/src/response.ts 77.14% 8 Missing ⚠️
packages/nest/src/filters/orpc-exception.filter.ts 93.54% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 29, 2025

More templates

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1149

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1149

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1149

@orpc/experimental-durable-iterator

npm i https://pkg.pr.new/@orpc/experimental-durable-iterator@1149

@orpc/hey-api

npm i https://pkg.pr.new/@orpc/hey-api@1149

@orpc/interop

npm i https://pkg.pr.new/@orpc/interop@1149

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1149

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1149

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1149

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@1149

@orpc/otel

npm i https://pkg.pr.new/@orpc/otel@1149

@orpc/experimental-publisher

npm i https://pkg.pr.new/@orpc/experimental-publisher@1149

@orpc/react

npm i https://pkg.pr.new/@orpc/react@1149

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@1149

@orpc/experimental-react-swr

npm i https://pkg.pr.new/@orpc/experimental-react-swr@1149

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1149

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1149

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@1149

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@1149

@orpc/standard-server-aws-lambda

npm i https://pkg.pr.new/@orpc/standard-server-aws-lambda@1149

@orpc/standard-server-fastify

npm i https://pkg.pr.new/@orpc/standard-server-fastify@1149

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@1149

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@1149

@orpc/standard-server-peer

npm i https://pkg.pr.new/@orpc/standard-server-peer@1149

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@1149

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1149

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1149

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1149

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@1149

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@1149

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1149

commit: 8366106

@Mathiasduc
Copy link
Author

Mathiasduc commented Oct 29, 2025

We can already change headers without requiring a return.

Not from inside a Nest/Express/Fastify middleware if the response has already been sent by Orpc

Modifying the response body is an anti-pattern and makes it incompatible with the generated openapi spec.

It is but, I feel like, this should not be a concern of this integration. There is legitimate reasons to modifying a response defined by Orpc and ways to do it so it will not break contract/specs.
For example:

  • If I'm using the standard compression middleware libs in Nest (same apply for the express and fastify integrations as they are today)
  • I want to add a header based on the body
  • I want to encrypt the response body

This features exist in Orpc eco-system, with plugin or external packages, and users can also implement them at the ORPC level (orpc's middleware/interceptors) but why not make it possible to delegate this features to the platform being integrated with, Nest in this case.
It will ease the progressive migration to orpc, thanks to not having to replicate, reimplement and maintain every unsupported feature.

But, indeed, it also let the door open to the users to shoot themselves in the foot and break their own contract and specs.
Should this integration (and other integrations too for that matter) close the door to some features of the platform being integrated with ? Users of this platform are using Nest/express/fastify middlewares as they are specified, designed and documented and will expect them to work with ORPC.
We do not think that limiting platform feature compatibility in the name of 'safety', is an acceptable trade off.

@Mathiasduc
Copy link
Author

We can move this discussion in an issue if you prefer

@unnoq
Copy link
Owner

unnoq commented Oct 29, 2025

I feel like, this should not be a concern of this integration.

Reasonable, and I agreed - I just don't want mess thing up by introducing new apis, if you do this good enough I have no reason to reject.

I want to encrypt the response body

I believe without return encrypt still work, because under the hook its only express middleware or fastify plugin.

@unnoq
Copy link
Owner

unnoq commented Oct 30, 2025

If I'm using the [standard compression](https://docs.nestjs.com/techniques/compression) middleware libraries in Nest (the same applies to the express and fastify integrations as they exist today):

  • I want to add a header based on the body
  • I want to encrypt the response body

After thinking about it more, can you provide real examples or popular npm packages that depend on this? Personally, I believe that under the hood they should be Express middleware or Fastify plugins - so I don't think they need return body here.

Also, regarding your implementation, we can't always return body because streaming may need to be sent manually, and this inconsistent behavior is something we should avoid as well.

}
})

resBody.once('error', error => res.destroy(error))
Copy link
Owner

Choose a reason for hiding this comment

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

In Node.js we manually send streaming responses, but in Fastify you return the stream - this creates inconsistent behavior.

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.

2 participants