blyat
blyat

Reputation: 23

Fastify fail to serialize response schema when using oneOf / anyOf at top level

this is my route:

fastify.route({
    method: "GET",
    url: "/foo/:foo_id",
    schema: {
        params: {
            foo_id: { type: "string" },
        },
        response: {
            200: {
                oneOf: [
                    { type: "string" },
                    { type: "number" },
                ],
            },
        },
    },
    handler: fooHandler,
})

when I try to start the server I get this error message:

{
    "code":"FST_ERR_SCH_SERIALIZATION_BUILD",
    "message":"Failed building the serialization schema for GET: /foo/:foo_id, due to error undefined unsupported",
    "statusCode":500,
    "stack":"FastifyError: Failed building the serialization schema for GET: /foo/:foo_id, due to error undefined unsupported
        at Boot.<anonymous> (/home/fooUser/repo/node_modules/fastify/lib/route.js:280:19)
        at Object.onceWrapper (events.js:421:28)
        at Boot.emit (events.js:327:22)
        at /home/fooUser/repo/node_modules/avvio/boot.js:153:12
        at /home/fooUser/repo/node_modules/avvio/plugin.js:269:7
        at done (/home/fooUser/repo/node_modules/avvio/plugin.js:201:5)
        at check (/home/fooUser/repo/node_modules/avvio/plugin.js:225:9)
        at internal/process/task_queues.js:153:7
        at AsyncResource.runInAsyncScope (async_hooks.js:186:9)
        at AsyncResource.runMicrotask (internal/process/task_queues.js:150:8)
        at processTicksAndRejections (internal/process/task_queues.js:97:5)"
}

I don't see anything wrong in my schema definition. It seems like it's not working only for the response schema. I tried the same schema for the body and for the foo_id and it worked properly:

params: {
    foo_id: {
        oneOf: [
            { type: "string" },
            { type: "number" },
        ],
    }
},
body: {
    oneOf: [
        { type: "string" },
        { type: "number" },
    ]
}

It is also working when I use oneOf inside the response schema but at a nested level, like so:

response: {
    200: {
        type: "object",
        properties: {
            foo: {
                oneOf: [
                    { type: "string" },
                    { type: "number" },
                ],
            }
        }
    },
}

I don't see why I can't define multiple schema for an http response, that does not make sense.

Upvotes: 2

Views: 3087

Answers (1)

Manuel Spigolon
Manuel Spigolon

Reputation: 12870

The issue is that fast-json-stringify doesn't support oneOf as the root object:

const fastJson = require('fast-json-stringify')

const serial = fastJson({
  type: 'object',
  properties: {
    response: {
      oneOf: [
        { type: "string" },
        { type: "number" },
      ],
    }
  }
})

console.log(serial(5));
console.log(serial("5"));

So you have a couple of solutions:

  1. send a PR to the module to add this feature 😀

  2. wrap your plain string/number prop to an object:

fastify.get('/', {
  schema: {
    response: {
      200: {
        type: 'object',
        properties: {
          response: {
            oneOf: [
              { type: "string" },
              { type: "number" },
            ],
          }
        }
      },
    },
  }
},...
  1. Write a custom serializer for these special cases in your handlers:
const fastify = require('fastify')({ logger: true })
fastify.get('/', {
  serializerCompiler({ schema, method, url, httpStatus }) {
    return (responsePayload) => {
      if (typeof responsePayload === 'string') {
        return `"${responsePayload}"`
      } else {
        return `${responsePayload}`
      }
    }
  },
  schema: {
    response: {
      200: {
        oneOf: [
          { type: "string" },
          { type: "number" },
        ],
      }
    },
  },
  handler: async () => { return Math.random() >= 0.5 ? 5 : '5' }
})

Upvotes: 1

Related Questions