Better JSON through streams – Requesting data – Sending a streamed response



Better JSON through streams – Requesting data – Sending a streamed response

1 2


better-json-through-streams-slides

The slides for "Better JSON through streams"

On Github JuanCaicedo / better-json-through-streams-slides

Better JSON through streams

Who am I?

Difficulties

  • Slow server response
  • Coupled responses
  • Big AJAX slow and brittle
  • Multiple AJAX = complexity
🤔

Unix streams

  • New-line separated text
  • Work with single data points
  • Collection of data over time

Javascript libraries

  • Oboe.js
  • Highland.js

Three streaming interfaces

  • Requesting data
  • Responding with data
  • Transfering within application

Requesting data

http://localhost:3000/just-html

Basic data endpoint

              
/* server */
router.get('/data-fs-async', function(req, res) {

  var catPath = 'filePath';

  fs.readFile(catPath, function(err, data){
    res.send(data);
  });

});
              
            
              
curl -s localhost:3000/data-fs-async | jq . | less
              
            

Ask for the data

              
/* client */
oboe('http://localhost:3000/data-fs-async')
              
            

Parse out each point

              
/* client */
oboe('http://localhost:3000/data-fs-async')
  .node('{x y color}', function(point) {

    // code using point

  })
              
            

Use each point

              
/* client */
oboe('http://localhost:3000/data-fs-async')
  .node('{x y color}', function(point) {

    var grid = document.querySelector('.grid');
    var cell = getCell(grid, point.x, point.y);
    cell.classList.add(point.color);

  });
              
            
http://localhost:3000/fs-async

Sending a streamed response

Basic data endpoint

              
/* server */
router.get('/data-basic', function(req, res) {

  var catPath = 'filePath';

  fs.readFile(catPath, function(err, data){
    res.send(data);
  });

});
              
            

Read as stream instead

              
/* server */
router.get('/data-fs-read-stream', function(req, res) {

  var dataStream = fs.createReadStream('filePath');

  dataStream.pipe(res);

});
              
            

Streams on the server

Two data sources

File on the server File over the network

Get both as streams

              
function getFullStream() {
  var catPath = path.resolve(__dirname, './cat-points.json');
  var catSource = fs.createReadStream(catPath);
  var catStream = getPointStream(catSource);

  var sunUrl = 'https://raw.githubusercontent.com/JuanCaicedo/better-json-through-streams/master/data/sun-points.json';
  var sunSource = request(sunUrl);
  var sunStream = getPointStream(sunSource);

  return highland([
      catStream,
      sunStream
    ])
    .merge();
}
              
            

Convert strings to points

              
function getPointStream(sourceStream) {

  return highland(function(push, next) {
    sourceStream.on('error', function(err) {
      push(null, highland.nil);
    });

    oboe(sourceStream)
      .node('{x y color}', function(point) {
        push(null, point);
      })
      .done(function() {
        push(null, highland.nil);
      });
  });

}
              
            

Organize and send

              
router.get('/full-data', function(req, res) {

  var pointStream = points.getFullStream()
        .map(JSON.stringify)
        .intersperse(',');

  highland([
      '['
      pointStream,
      ']'
    ])
    .invoke('split', [''])
    .sequence()
    .pipe(res);
});
              
            
http://localhost:3000/

All done!

Better JSON through streams