compileSerializationSchema reuses the first serializer when metadata changes
- Dominant language
- JavaScript
- Stars
- 37.1k
- Forks
- 3k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 13
Description
### Description
`reply.compileSerializationSchema()` forwards `httpStatus` and `contentType` to a custom serializer compiler, but its cache is keyed only by the schema object. Reusing the same schema object with different metadata therefore returns the serializer compiled for the first call.
This is present on `main` at `1beaf7e72d24b2fc63a02a7f5806772a00e45454`:
- [`compileSerializationSchema` checks and stores by schema identity only](https://github.com/fastify/fastify/blob/1beaf7e72d24b2fc63a02a7f5806772a00e45454/lib/reply.js#L373-L408)
- [The documentation says both optional values are forwarded to a custom compiler](https://github.com/fastify/fastify/blob/1beaf7e72d24b2fc63a02a7f5806772a00e45454/docs/Reference/Reply.md#L426-L437)
### Reproduction
```js
const Fastify = require('fastify')
const app = Fastify()
const compiled = []
app.setSerializerCompiler(({ httpStatus, contentType }) => {
compiled.push({ httpStatus, contentType })
return (data) => JSON.stringify({ httpStatus, contentType, data })
})
app.get('/', (_request, reply) => {
const schema = { type: 'object' }
const first = reply.compileSerializationSchema(schema, '200', 'application/json')
const second = reply.compileSerializationSchema(schema, '201', 'application/vnd.example+json')
return {
sameFunction: first === second,
compiled,
first: first({ value: 1 }),
second: second({ value: 2 }),
}
})
app.inject({ method: 'GET', url: '/' }).then(({ payload }) => console.log(payload))
```
### Actual behavior
The compiler is invoked once, `sameFunction` is `true`, and both calls use the `200` / `application/json` metadata captured by the first serializer.
### Expected behavior
Changing `httpStatus` or `contentType` should produce (or retrieve) a serializer compiled for that metadata tuple.
### Possible direction
Keep the weak schema identity cache, but store serializers below it by `httpStatus` and `contentType`, including a stable representation for omitted values.
I found this while benchmarking an automated code-review workflow and manually verified the source path and reproduction before reporting it.
Contributor guide
Research direction
Read lib/reply.js at compileSerializationSchema and compare its cache behavior with the forwarding contract in docs/Reference/Reply.md. Use the supplied reproduction to verify the behavior; done when serializers are reused only for identical schema and metadata tuples and metadata changes produce matching serializers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100