Search code examples
javascriptnode.jshttpexpressnode-sqlite3

Having issues responding to an HTTP request with the proper array. Possible way to send results from within function with expressjs?


Problem Summary: So I'm working on a program that has an SQL database on the backend and I'm using the npm SQLite3 module to talk to it. When I make my HTTP request to the server I was told in another post that I should do a res.send with the function inside it so after the function ran, it would return whatever came from the function. Easy enough right? But then I ran into an issue with an asynchronous function .all (API Doc here). Essentially what happens is that I call my database and it returns everything inside to an object inside database.all, but database.all is an asynchronous function that is void and can't return anything. I've got a callback that sends the object inside the callback, but I don't know what to do with it from there, or if I even need a callback.

So my question is: can I send an HTTP response from somewhere inside my .all function or callback, or does my function have to return the array to where it was called? Code below to show you what I mean.

Chain of events (Github repo for refrence):

I've set up an angular controller to send the following HTTP request when my page loads:

$http.get('/LoadWaitingList')
.then(function(response) {
    // alert("HTTP request set, getting data");
    console.log(response.data);
});

and when the server (server.js) receives it, I do this:

app.get('/LoadWaitingList', function (req, res) {
  res.send(DatabaseFunction.loadWaitingList());
})

which runs the loadWaitingList() function in another file named test.js:

function  loadWaitingList() {
    var callbackFunction = function(err, response){
        var returnRow = response;
        return returnRow;
    }
    updateDB.Manager(callbackFunction);
}

which calls updateDB.Manager, AKA this guy:

Manager : function(callback){
    var fs = require("fs");
    var file = "./Source/Server/Data/DaycareDB.db";
    var exists = fs.existsSync(file);
    if (!exists) {
        throw new Error("File not Found");
    }
    var sqlite3 = require("sqlite3").verbose();
    var db = new sqlite3.Database(file);
    db.all("SELECT * FROM WaitingList", function(err, row) {
        if (err){
            callback(err);
            return;
        }
        // console.log(row[0].ChildName);                   
        callback(null, row);
        return;
    });
},

So finally we can see, after db.all runs, the values I'm after after in row. row is passed into db.all as a parameter and returned as an array, I've tried declaring it outside the db.all and passing it in and then printing out the results, but due to db.all being asynchronous it always comes up empty because the function hasn't run yet.

When I run my callback and check the object (using vscode debugger) after the callback has been called, returnRow has the proper data in it from my database.

How do I send the data that gets put into row and eventually returnRow back as a response? Is it possible to do the initial function call when we get the HTTP request a different way and then do a res.send from the callback or something?


Solution

  • You need to look at your callbacks.

    app.get('/LoadWaitingList', function (req, res) {
      DatabaseFunction.loadWaitingList(function(err,data){
        if(err) {
          // handle the error here
        }
        // send the data
        res.send(data);
      }
    });
    

    Now loadWaitingList() needs to take a standard error-first callback as a parameter. This callback is passed through to updateDB.Manager() where it will be executed.

    function loadWaitingList(callback) {
      updateDB.Manager(callback);
    }