Skip to content
This repository has been archived by the owner on Sep 18, 2019. It is now read-only.

How to pass a database connection to plugins? #182

Closed
electerious opened this issue Oct 25, 2015 · 15 comments
Closed

How to pass a database connection to plugins? #182

electerious opened this issue Oct 25, 2015 · 15 comments

Comments

@electerious
Copy link

Hi,

I'm trying to pass an open database connection to a Hapi plugin using the options property. The given connection is available inside the plugin, but it looks like the connection object has been passed to it as a value and not as a reference.

// Server
server.register([{
    register : require(nodePath),
    options  : { connection }
}], options, next)
// Plugin
// […]
plugin = function(server, options, next) {
    console.log(options.connection) // => Works fine
}
// […]

rethinkdb throws the following error:

Unhandled rejection ReqlDriverError: First argument to `run` must be an open connection.

What's the best way to pass a connection to a plugin?

Hapi Version: 11.0.2

Thanks for the help.

@gergoerdosi
Copy link

If you use "hapi-rethinkdb" then it exposes the connection (https://github.com/ghostbar/hapi-rethinkdb/blob/master/index.js#L26) that you can use in your plugin:

const connection = server.plugins['hapi-rethinkdb'].connection;

You will also need to make "hapi-rethinkdb" a dependency of your plugin.

@hueniverse
Copy link

The right way to do this is via the server.app namespace or using server.bind() if you are within a single plugin. I use the bind option when my application is structured as a single plugin (e.g. the API plugin and the Web plugin) and the app namespace option when I need to share a connection between separate plugins. Using server.expose() is bad design for this. Also passing this in the plugin options is messy and requires a lot of manual overhead.

I usually also set up an onRequest extension which copies server.app.db to request.app.db so that I don't have to type request.server.app.db in handlers. If I use the bind option, I just bind to something like { db: connection, config: {} } and then in each request I just use this.db.

@lkptrzk
Copy link

lkptrzk commented Oct 26, 2015

Using server.expose() is bad design for this.

Why? Also, what's the intended usage of server.expose then, server methods where you don't need caching?

Confused because my general rule was "share functions as methods, and other stuff via expose"

@hueniverse
Copy link

server.expose() should be used to control the inner workings of the plugin. For example, empty its cache or change state for processing requests. It is not meant as a generic API provide. For that, just use node modules. Server methods are common utilities used around your server, but best to not cross plugin boundaries with them to reduce dependencies.

In general, if you find yourself using a lot of dependencies between your own application plugins, you are doing it wrong.

@electerious
Copy link
Author

Thanks for the suggestions :) I will try the server.app namespace.

@hueniverse Was my assumption correct that objects passed to plugins as options are copies instead of reverences? Would be helpful to mention it in the docs if so. Hard to find out without any information/help.

@hueniverse
Copy link

@electerious it should not be cloning the options. If it does ,it's a bug.

@gergoerdosi
Copy link

@hueniverse The comment says:

this.app = {}; // Place for application-specific state without conflicts with hapi, should not be used by plugins

So which one is true? Can plugins (external modules, for example hapi-rethinkdb) add properties to server.app?

@hueniverse
Copy link

They should not. They should use the plugins namespace. But using plugins to load a db connection is an odd pattern.

@electerious
Copy link
Author

Finally had time to try server.app, but server.app is empty when I try to access it in the plugin.

Here's my code:

// --- Main application ---
console.log(1, data) // 1, {…}
server.app = data
console.log(2, server.app) // 2, {…}

// --- Plugin ---
plugin = function(server, options, next) {

    console.log(3, server.app) // 3, {}

}

plugin.attributes = {

    pkg: require('../../package')

}

module.exports = plugin

The plugin gets registered after setting server.app. Console output:

1, {} // Filled object
2, {} // Filled object
3, {} // Empty object

I'm using the newest hapi.js version (11.1.2). Is there anything I'm doing wrong? Should be correct according to docs.

@johnbrett
Copy link

You need to use server.root.app inside a plugin to access app here.

@electerious
Copy link
Author

@johnbrett Thanks a lot! :) Works.

RethinkDB still says Unhandled rejection ReqlDriverError: First argument to 'run' must be an open connection.. I'm not sure why (and if) the connection gets closed. RethinkDB close-event never fires so I assume that the connection is fine.

@devinivy
Copy link

I don't think that last issue is hapi-related. In any case, perhaps the connection hasn't closed, but rather hasn't opened yet.

@electerious
Copy link
Author

Yes, I don't think it's an hapi.js issue/problem anymore. I will try to find a solution and keep this thread updated. Thanks for the help!

@hueniverse
Copy link

server.app is always the same as server.root.app. It is not a plugin specific reference.

@electerious
Copy link
Author

Finally found the problem 🎉

The provided error is misleading. It's not the connection, it's the rethinkdb module! I import/require it in the main application and inside plugins. It's the same module, but a different instance of it. The connection itself is the same and still open.

Passing the connection AND the rethinkdb instance to plugins works. Passing the connection to plugins and using their rethinkdb does not. The connection must be from the same instance as later used to get data from the database.

Passing everything down to plugins is a bad idea and I will try to find a better solution.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants