Search code examples
node.jshapi.jstedious

Node/Hapi.js - How to stream/append result set from database via hapi.js?


I'm trying to create REST service that returns data from database as a response via hapi.js.

I'm using tedious to execute SQL queries and I want to format results as JSON or XML and return them as a response of hapi request. Note that this is not tedious-specific, I can have the same problem with any database. Tedious has a callback that is invoked each time it receives a new row from the result set:

sqlRequest.on('row', function (columns) {
        fnOutput(columns[0].value);
});

This is the simplest example with one column output. fnOutput is a custom function that accepts text that should be returned. It can concatenate results and format them as JSON that will be returned to client.

I'm getting row-by-row and I want to concatenate values in rows and return them to the client via hapi. How to continuously send partial results to the response?

  1. I don't want to concatenate all rows in this callback and then push entire formatted JSON when the query is finished. I don't know how many records I will have and I want to avoid big strings that will be accumulated.
  2. If I try to call reply(columns[0].value) in fnOutput each time I get new row, it fails when second row is returned with: "reply interface called twice"

Is there some way to continuously append results in this callback to hapi.js output stream each time I get new row in callback function?


Solution

  • You may be able to write the data to the raw response using request.raw.res.write()

    request.raw.res is the raw ServerResponse object, and you can find the documentation for the write method here: https://nodejs.org/dist/latest-v4.x/docs/api/http.html#http_response_write_chunk_encoding_callback

    Once you are done writing data, you'll need to tell hapi that you are done handling the request manually by calling reply.close()

    Something similar to this (untested):

    sqlRequest.on('row', function (columns) {
        request.raw.res.write(columns[0].value);
    });
    
    sqlRequest.on('done', function () {
        reply.continue();
    });