Closed crishoj closed 1 week ago
To be clear: Developers likely don't expect side-effects from using objects as response bodies. This can lead to subtle and surprising errors with long-lived objects, and kind of breaks strong typings in the app codebase.
I would suggest:
structuredClone()
on the response body before cleaning.normalize
independently configurable for incoming request data and outgoing response data. Mutating incoming data is fine, but directly mutating objects used in responses can break DX.@SaltyAom — what do you think about the proposed change https://github.com/crishoj/elysia/commit/d759a6f59bf01ca3e7486375a2533cbdf327af3c?
Also removed redundant logic — all three cases do exactly the same thing.
Updated with example to reproduce.
I think we shouldn't do it by default. It as typebox do And structuredClone is perfomance killer
I would be happy with an option as well.
Perhaps:
clean
→ mutatesnormalize
→ clone then clean (doesn't mutate)none
→ no normalization, extra attributes in responses causes validation errorI would be happy with an option as well.
Perhaps:
clean
→ mutatesnormalize
→ clone then clean (doesn't mutate)none
→ no normalization, extra attributes in responses causes validation error
Yeah it's interesting Something like union type But clean should be by default
If u want to use clean and no mutate something u can just place structuredClone in u handler/hook
Perfomance is a important goal of elysia (like JIT code-generation at runtime) so no need to call structuredClone on everything
I would argue that DX should also be an important goal. Frankly speaking, seeing long-lived objects referenced in responses being mutated by Elysia/Typebox was a terrifying gotcha for me.
Perhaps a reasonable default could be to error in case responses don't match the type sanctioned by the schema.
Then, let the developer make an explicit choice:
I would argue that DX should also be an important goal. Frankly speaking, seeing long-lived objects referenced in responses being mutated by Elysia/Typebox was a terrifying gotcha for me.
Perhaps a reasonable default could be to error in case responses don't match the type sanctioned by the schema.
Then, let the developer make an explicit choice:
- Use mutating cleaning to minimize response time.
- Use clone+clean to maintain type safety.
Long-lived objects is not so often case If u need to prevent mutation just clone it But i agree that it should be more warned in the docs
What version of Elysia is running?
1.1.23
What platform is your computer?
macOS
What steps can reproduce the bug?
With normalize
true
(the default), Elysia will mutate objects used in responses.Consider this example with a long-lived object
people
:What is the expected behavior?
From a developer perspective, I expect Elysia to not directly mutate objects used in a response body.
If response normalization is active, I expect cleaning to happen on a (deep) clone of the object passed as response body.
What do you see instead?
Objects used in responses are directly mutated — additional properties are deleted by the Typebox cleaner:
Additional information
This caught me off guard and led to subsequent errors in my app where properties in a long-lived object were suddenly undefined.
For improved DX, please consider doing a
structuredClone()
of objects before normalization.Have you try removing the
node_modules
andbun.lockb
and try again yet?Yes