0

I'm new to NodeJS and Fastify and I'm fairly sure I'm making a basic mistake here but I can't see what it is.

I have separated out my MySQL connection and routes into separate plugins. It appears that the MySQL plugin is not registering in time, leading to the routes not working.

I was under the impression that registering plugins was done asynchronously (loading one plugin at a time), but it can't seem to find "fastify.mysql.query".

Error:

"Cannot read properties of undefined (reading 'query')","stack":"TypeError: Cannot read properties of undefined (reading 'query')\n    at Object.<anonymous> (/Users/dally/Projects/NodeJS/boodil-payments-api/routes/payments.js:4:23)\n    at preHandlerCallback (/Users/dally/Projects/NodeJS/boodil-payments-api/node_modules/fastify/lib/handleRequest.js:126:28)\n    at preValidationCallback (/Users/dally/Projects/NodeJS/boodil-payments-api/node_modules/fastify/lib/handleRequest.js:110:5)\n    at handler (/Users/dally/Projects/NodeJS/boodil-payments-api/node_modules/fastify/lib/handleRequest.js:74:7)\n    at handleRequest (/Users/dally/Projects/NodeJS/boodil-payments-api/node_modules/fastify/lib/handleRequest.js:22:5)\n    at runPreParsing (/Users/dally/Projects/NodeJS/boodil-payments-api/node_modules/fastify/lib/route.js:487:5)\n    at Object.routeHandler [as handler] (/Users/dally/Projects/NodeJS/boodil-payments-api/node_modules/fastify/lib/route.js:434:7)\n    at Router.lookup (/Users/dally/Projects/NodeJS/boodil-payments-api/node_modules/find-my-way/index.js:368:14)\n    at Server.emit (node:events:527:28)\n    at parserOnIncoming (node:_http_server:956:12)"},"msg":"Cannot read properties of undefined (reading 'query')"}

Server.js

const fastify = require('fastify')({ logger: true })
fastify.register(require('./config/db'))
fastify.register(require('./routes/payments'))
const PORT = 2000

const start = async () => {
    try {
        await fastify.listen({ port: PORT })
    }
    catch (e) {
        fastify.log.error(e)
        process.exit(1)
    }
}

start()

DB.js

module.exports = function (fastify, options, done) {
    fastify.register(require('@fastify/mysql'), {
        connectionString: 'mysql://root:password@localhost/boodil'
    })

    done()
}

payment.js

function paymentRoutes(fastify, opts, done) {

    fastify.get('/get-transactions', (req, reply) => {
        fastify.mysql.query(
            'SELECT * FROM transactions',
            function onResult(err, result) {
                reply.send(err || result)
            }
        )
    })

    fastify.get('/get-transaction:id', (req, reply) => {
        fastify.mysql.query(
            'SELECT * FROM transactions where id = ?', [req.params.id], 
            function onResult(err, result) {
                reply.send(err || result)
            }
        )
    })

    done()
}

module.exports = paymentRoutes
Dally
  • 1,281
  • 4
  • 18
  • 37
  • I can't add more details right now, but you need to use fastify-plugin in your dB.js file otherwise the two contexts does not see each other – Manuel Spigolon Aug 30 '22 at 06:30
  • Is this normal in Fastify @ManuelSpigolon? Does Fastify not support dependency injection by default? Seems like a weird thing to not have unless I'm missing something. I'm coming from a PHP/Laravel background where this is quite standard. – Dally Aug 30 '22 at 09:56

1 Answers1

0

As said in comments, you need to use the fastify-plugin wrapper in your DB.js file.

To understand this error, you must get confident with fastify's encapsulation context.

It is worth reading these answers:

In practice: your database connection was isolated into a context that was unreachable by the paymentRoutes.

I'm coming from a PHP/Laravel background where this is quite standard

What fastify refuses is creating a global context where all you need is shared. Of course, you can do it, by it is not the default behaviour. You need to declare that the exported plugin has something that can be used by other contexts.

Manuel Spigolon
  • 11,003
  • 5
  • 50
  • 73