Reputation: 336
Playing with fastify and the schema object on routes, I'm trying to add more validations. fastify use (for body validations) ajv. Following fastify documentation and code, to add a ajv plugin I need to do this:
const fastify = require('fastify')({
ajv: {
plugins: [
require('ajv-merge-patch')
]
}
})
The documentation is here
The problem is that when we try to add this plugin, I receive this error: Cannot read property 'code' of undefined"
and this is the stack error:
TypeError: Cannot read property 'code' of undefined
at addFormats (/test-api/node_modules/ajv-formats/dist/index.js:30:26)
at Array.formatsPlugin (/test-api/node_modules/ajv-formats/dist/index.js:15:5)
at ValidatorCompiler (/test-api/node_modules/fastify/lib/schema-compilers.js:42:16)
at buildCompilerFromPool (/test-api/node_modules/fastify/lib/schema-compilers.js:20:22)
at Boot.<anonymous> (/test-api/node_modules/fastify/lib/route.js:269:39)
at Object.onceWrapper (events.js:421:28)
at Boot.emit (events.js:327:22)
at /test-api/node_modules/avvio/boot.js:153:12
at /test-api/node_modules/avvio/plugin.js:269:7
at done (/test-api/node_modules/avvio/plugin.js:201:5)"
I get this error with this piece of code:
const server: FastifyInstance<Server, IncomingMessage, ServerResponse > = fastify({
ignoreTrailingSlash: true,
logger: true,
ajv: {
plugins: [
require('ajv-formats')
]
}
})
async function run (): Promise<string> {
server.addHook('onRoute', (options) => console.log(options))
await server.register(helmet)
await server.register(cors)
return server.listen(3000, 'localhost')
}
Has anyone been able to use ajv-formats
with fastify or could you help me, please?
Thanks in advance!
Upvotes: 3
Views: 3400
Reputation: 524
Had the same issue so I decided to use Ajv version 8.x.x and use other plugins within.
import Ajv from "ajv";
import ajvFormats from "ajv-formats";
import ajvErrors from "ajv-errors";
const ajv = new Ajv({
removeAdditional: true,
useDefaults: true,
coerceTypes: true,
allErrors: true
});
ajvFormats(ajv);
ajvErrors(ajv, { singleError: true });
export { ajv };
After that, I've just used this Ajv instance for schema compilation in the Fastify server as suggested in the the docs.
fastify.setValidatorCompiler((opt) => ajv.compile(opt.schema));
It works without any problems. The same result is achievable with regular JavaScript.
Upvotes: 2
Reputation: 70
I had the same issue and decided to look into the cause. The problem is that ajv-formats
depends on ajv 8.x.x
while fastify
depends on ajv 6.x.x
. These two are incompatible.
There are multiple solutions
fastify
to support ajv 8.x.x
. This is a work in progressajv
-Plugin and add that to fastify
. A plugin is a function that takes the ajv
instance as first parameter1. There you can add the formats, take a look at ajv-formats
to see how it is done there.ajv-formats
. Sadly the last version of ajv-formats
to support ajv 6.x.x
is 0.2.0 (take a look at package.json). Not a good option IMO1Plugins can also take options but there are no Typescript typings to add such plugins to fastify
.
Upvotes: 1
Reputation: 336
Solved! Seems to be that my problems come from another part of my code. Creating a new project form 0 and using format seems to works well and I don't need to install ajv-format, because fastify has the option format to use in your schemas!
Thanks to all!
Upvotes: 0
Reputation: 12900
Here a working example you may customize:
"ajv-merge-patch": "^4.1.0",
"fastify": "^3.9.2",
"fastify-cors": "^5.1.0",
"fastify-helmet": "^5.1.0",
const fastify = require('fastify')({
ignoreTrailingSlash: true,
logger: true,
ajv: {
plugins: [
require('ajv-merge-patch')
]
}
})
fastify.register(require('fastify-cors'))
fastify.register(require('fastify-helmet'))
fastify.addSchema({
$id: 'mySchema.json#',
type: 'object',
properties: {
foo: { type: 'string' },
bar: { $ref: '#' }
},
additionalProperties: false
})
fastify.post('/', {
schema: {
body: {
$id: 'mySchemaExtended.json#',
$merge: {
source: { $ref: 'mySchema.json#' },
with: {
properties: {
baz: { type: 'number' }
}
}
}
}
}
}, (req, reply) => { reply.send({ echo: req.body }) })
fastify.inject({
method: 'POST',
url: '/',
payload: {
foo: 'foo',
bar: {
foo: 'foo2',
evit: 'this'
},
baz: 42,
evict: 'this too'
}
}, (err, res) => {
console.log(res.json());
// shows
// { echo: { foo: 'foo', bar: { foo: 'foo2' }, baz: 42 } }
})
Upvotes: 0