knoll
knoll

Reputation: 295

Express Routing - Database Calls and Scope

I've got a small Node/Express app that simply displays data on a page from several Postgres tables. My database connection/querying function lives in a separate file (db.js) as do my queries (queries.js). My question is how best to handle variable scope in my calls to the db connection function.

Here's an example:

// Module imports
var express = require('express');
var router = express.Router();
var config = require('../lib/config');
var db = require('../lib/db');
var queries = require('../lib/queries');


// GET /
router.get('/', function(req, res) {

    db.dataTalk(queries.qOne, null, config.aws, function(err, result) {
        if (err) {
            res.render('error', {err: err, flavor: 'Having trouble talking to the database.', title: 'Error'});
        } else {
            var qOneResults = result;
        }

    db.dataTalk(queries.qTwo, null, config.aws, function(err, result) {
        if (err) {
            res.render('error', {err: err, flavor: 'Having trouble talking to the database.', title: 'Error'});
        } else {
            var qTwoResults = result;
        }

    res.render('index', {
        title: 'Page Title',
        qOneResults: qOneResults,
        qTwoResults: qTwoResults
    });
    });
    });
    return;
});

My linter displays a warning on line 29 saying that qTwoResults is out of scope. If I want to display more data on a page, and need to make more database requests in a given route, what's the best way to call that function while maintaining proper scope?

Upvotes: 0

Views: 271

Answers (2)

jfriend00
jfriend00

Reputation: 707476

It's probably a misleading error. var declarations are automatically hoisted to the top of their containing function so qTwoResults always exists at the point you are using it and it is in scope for the entire function. But putting the declaration inside a block and then using it outside of that block is just bad form (something linters often tell you about).

It may also be referring to the fact that you've declared and initialized qTwoResults inside an if block that may or may not get called before you try to use the value which isn't technically a script error, but is usually bad form.

Also, whenever you call res.render(), you need to return so you don't keep executing the rest of your code and subsequently try to call render again.

I'd suggest this code block that makes the following changes:

  1. Name your result arguments appropriate so you don't need to declare or assign new variables.
  2. Put your follow-on code inside the if/else so you can only ever call res.render() once.

Code:

// GET /
router.get('/', function(req, res) {
    db.dataTalk(queries.qOne, null, config.aws, function(err, qOneResults) {
        if (err) {
            res.render('error', {err: err, flavor: 'Having trouble talking to the database.', title: 'Error'});
        } else {
            db.dataTalk(queries.qTwo, null, config.aws, function(err, qTwoResults) {
                if (err) {
                    res.render('error', {err: err, flavor: 'Having trouble talking to the database.', title: 'Error'});
                } else {
                    res.render('index', {title: 'Page Title', qOneResults, qTwoResults});
                 }
            });
        }
    });
});

Upvotes: 1

Joe Lissner
Joe Lissner

Reputation: 2472

Your linter probably thinks it's out of scope, changing to to this should fix the issue:

// Module imports
var express = require('express');
var router = express.Router();
var config = require('../lib/config');
var db = require('../lib/db');
var queries = require('../lib/queries');


// GET /
router.get('/', function(req, res) {
    var qOneResults, qTwoResults; // declare the variables here

    db.dataTalk(queries.qOne, null, config.aws, function(err, result) {
        if (err) {
            res.render('error', {err: err, flavor: 'Having trouble talking to the database.', title: 'Error'});
        } else {
            qOneResults = result;
        }

        db.dataTalk(queries.qTwo, null, config.aws, function(err, result) {
            if (err) {
                res.render('error', {err: err, flavor: 'Having trouble talking to the database.', title: 'Error'});
            } else {
                qTwoResults = result;
            }

            res.render('index', {
                title: 'Page Title',
                qOneResults: qOneResults,
                qTwoResults: qTwoResults
            });
        });
    });
    return;
});

Upvotes: 1

Related Questions