Skip to content

Commit b1aae8e

Browse files
authored
Merge pull request #905 from crishoj/avoid-normalization-side-effects
Avoid response normalization side-effects
2 parents e715e00 + 21d8ec5 commit b1aae8e

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

src/utils.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -715,13 +715,7 @@ export const getResponseSchemaValidator = (
715715

716716
const compile = (schema: TSchema, references?: TSchema[]) => {
717717
const cleaner = (value: unknown) => {
718-
if (!value || typeof value !== 'object')
719-
return Value.Clean(schema, value)
720-
721-
if (Array.isArray(value)) value = Value.Clean(schema, value)
722-
else value = Value.Clean(schema, value)
723-
724-
return value
718+
return Value.Clean(schema, structuredClone(value))
725719
}
726720

727721
if (dynamic)

test/core/normalize.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,39 @@ describe('Normalize', () => {
432432
expect(response.status).toBe(422)
433433
})
434434

435+
it('response normalization does not mutate', async () => {
436+
// Long-lived object has a `token` property
437+
const service = {
438+
name: 'nagisa',
439+
status: 'online',
440+
token: 'secret',
441+
}
442+
443+
// ...but this property is hidden by the response schema
444+
const responseSchema = t.Object({
445+
name: t.String(),
446+
status: t.String(),
447+
})
448+
449+
const app = new Elysia({
450+
normalize: true,
451+
}).get('/test', () => service, {
452+
response: responseSchema,
453+
})
454+
455+
expect(service).toHaveProperty('token')
456+
const origService = structuredClone(service)
457+
458+
const response = await app.handle(new Request('http://localhost/test'))
459+
expect(response.body).not.toHaveProperty('token')
460+
461+
// Expect the `token` property to remain present after `service` object was used in a response
462+
expect(service).toHaveProperty('token')
463+
464+
// In fact, expect the `service` to not be mutated at all
465+
expect(service).toEqual(origService)
466+
})
467+
435468
// it('normalize response with getter fields on class', async () => {
436469
// const app = new Elysia({
437470
// normalize: true

0 commit comments

Comments
 (0)