Search code examples
node.jsserializationbigintegerfastify

Could someone help me to create a HOOK in FASTIFY to automatically serialize these types of values ​in all app.ts endpoints?


Could someone help me to create a HOOK in FASTIFY to automatically serialize these types of values ​​in all app.ts endpoints

Code image Error image

I managed to solve the problem using .toString, but I wanted a way to do this automatically in all requests


Solution

  • First of all, bigint is not supported by JS standard functions:

    const big = { n: :1231231231231231213n }
    console.log(typeof big.n) // bigint
    JSON.stringify(big) // TypeError: Do not know how to serialize a BigInt
    
    JSON.parse('{"n":1231231231231231213}') // { n: 1231231231231231200 }
    

    Here is 3 solutions:

    1. set a json schema response and fastify will do it for you by converting them into numbers!
    2. take ownership of the serialization with preSerialization hook. Note that the toString returns a string a not a number
    3. take ownership of the serialization with setReplySerializer. Different approach but same result as before.

    I would use something that gives fully control over the serialization, because serializing bigint is not supported by the JSON.* utilities and the client who parse the json must be aware of it or it will fail! See the code snippet above, JSON.parse() trims the number.

    const app = require('fastify')({ logger: true })
    
    app.get('/solution-1', {
      schema: {
        response: {
          200: {
            type: 'object',
            properties: {
              n: { type: 'number' }
            }
          }
        }
      }
    }, async (request, reply) => {
      return { n: 1231231231231231213n } // prints {"n":1231231231231231200} (not a string 🚀)
    })
    
    app.register(function plugin (app, opts, next) {
      app.addHook('preSerialization', async (request, reply, payload) => {
        payload.n = payload.n.toString()
        return payload
      })
    
      app.get('/solution-2', async (request, reply) => {
        return { n: 1231231231231231213n } // prints {"n":"1231231231231231213"}
      })
    
      next()
    })
    
    app.register(function plugin (app, opts, next) {
      app.setReplySerializer(function (payload, statusCode) {
        return JSON.stringify(payload, (key, value) =>
          typeof value === 'bigint'
            ? value.toString()
            : value
        )
      })
      app.get('/solution-3', async (request, reply) => {
        return { n: 1231231231231231213n } // prints {"n":"1231231231231231213"}
      })
    
      next()
    })
    
    app.listen({ port: 8080 })
    
    curl http://localhost:8080/solution-1
    curl http://localhost:8080/solution-2
    curl http://localhost:8080/solution-3