Express & Socket.io

Intro

  • Express: "Fast, unopinionated, minimalist web framework for Node.js"
  • Socket.io: Nice websocket abstraction 

 

expressjs.com

socket.io

Getting started

Set up a simple Node project:

npm init
npm install --save express socket.io
npm install --save-dev nodemon
touch index.js

# edit package.json to add a start script
#
#    "scripts": {
#      "test": "echo \"Error: no test specified\" && exit 1",
#      "start": "nodemon index"
#    },

Set up Express

index.js

// dependencies
const express = require('express');
const socketio = require('socket.io');
const http = require('http');


// create an express app instance
// and an HTTP server that listens for it.
const app = express();
const server = http.Server(app);


// start the server
server.listen(3000, () => {
  console.log(`express is running on port 3000`);
});

Set up Express

Now we have an Express app listening on port 3000 that does nothing but send 404s, so we need to add routes.

 

Routes are how we say:

 

"When a user asks for this, give them that"

Routes

Create and use an Express Router

// create a router and configure some routes
const router = new express.Router();

router.get('/', (req, res) => {
  res.status(200).send('Hello World');
});

router.post('/', (req, res) => {
  res.status(201).send('POST OK');
});



// use the router in the / namespace
app.use('/', router);

More interesting routes

Routes with parameters

// a route with a parameter
router.get('/hello/:name', (req, res) => {
  res.status(200).send(`Hello ${req.params.name}`);
});

Middleware

  • Middleware intercepts requests, does something and passes them on.
  • The Router is middleware.
// use middleware to log all requests
app.use('/', (req, res, next) => {
  console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);
  next();
});


// use a router so the app knows what it's doing
app.use('/', router);

Middleware

  • Middleware matches the path and all sub-paths
  • So / will catch every route
  • /foo will catch /foo and /foo/bar/lalala
  • Middleware is executed in the order it's declared
  • Finish the response cycle!
    • Either call next()
    • Or send a response with res.send()

Middleware

A lot of the time you'll utilise third party middleware

const morgan = require('morgan');


// morgan for logging
app.use('/', morgan());

// express.static to serve our static files
app.use('/static', express.static('client'));

Back to the task at hand!

  • That's how Express works in a nutshell.
  • So let's get some Sockety goodness happening.

Serve our client app

Respond with a file using res.sendFile()

// send index.html
router.get('/', (req, res) => {
  res.sendFile(__dirname + '/client/index.html', {}, (err) => {
    if (err) {
      res.status(err.status).end();
    }
  });
});

Enter socket.io

Pass the Express server to socket.io

// create an express app instance
// and an HTTP server that listens for it.
// pass the server to socket.io

const app = express();
const server = http.Server(app);
const io = socketio(server);

Make a client app

Some basic JS to log things to the page

// log a string
// we have a div with id #console on the page
function log(str) {
  const pre = document.createElement('pre');
  pre.textContent = str;
  document.querySelector('#console').appendChild(pre);
}

log('now you have a console');

Connect to the socket

Connect and start logging events

// in our index.html we're adding 
// <script src="/socket.io/socket.io.js"></script>
// which socket.io automatically provides us via Express


// meanwhile, in our client JS, we'll connect to that and 
// start logging events...

const socket = io();

socket.on('connect', () => {
  log('connected to socket');
});

socket.on('disconnect', () => {
  log('disconnected from socket');
});

Connect to the socket

Log connections on the server

const io = socketio(server);


// listen for socket events
io.on('connection', (socket) => {
  console.log('socket connected');
});

Finally the good stuff

Emit events from the server to the client

const io = socketio(server);


// listen for socket events
io.on('connection', (socket) => {
  console.log('socket connected');

  // `socket` argument is the socket connection 
  // to that specific client
  socket.emit('message', 'hey there');

});

Finally the good stuff

And log them on the client

// messages. log them.
socket.on('message', str => {
  log(str);
});

Spreading the news

Now let's emit a message to ALL clients

// listen for socket events
io.on('connection', (socket) => {
  console.log('socket connected');

  // `socket` is our connection to that user
  socket.emit('message', 'hey there');

  // tell everybody that we just connected
  io.emit('message', 'someone connected');
});

But don't go overboard

Emit a message to all other clients, with broadcast

// listen for socket events
io.on('connection', (socket) => {
  console.log('socket connected');

  // `socket` is our connection to that user
  socket.emit('message', 'hey there');

  // tell everybody else that we just connected
  socket.broadcast.emit('message', 'someone connected');
});

Emit whatever you want

Emit different events to do different things.

// listen for socket events
io.on('connection', (socket) => {
  console.log('socket connected');

  // `socket` is our connection to that user
  socket.emit('message', 'hey there');
  socket.emit('alert', 'KAPOW');

  // tell everybody else that we just connected
  socket.broadcast.emit('message', 'someone connected');
});
// this won't annoy anybody
socket.on('alert', (str) => {
  alert(str)
});

Back the other way 

Let's emit an event from the client to the server

// server

// listen for socket events
io.on('connection', (socket) => {

  socket.on('ayo', () => {
    console.log('ayo!');
  });

});
// client
document.querySelector('button').addEventListener('click', (evt) => {
  socket.emit('ayo');
});

Request-Response

Client to server and back again

// server

// listen for socket events
io.on('connection', (socket) => {

  socket.on('ayo', (payload, callback) => {
    console.log('ayo!');
    callback('right back at you');
  });

});
// client
document.querySelector('button').addEventListener('click', (evt) => {
  socket.emit('ayo', {}, response => {
    log(response);
  });
});

Rooms

A simple abstraction for grouping connections

// listen for socket events
io.on('connection', (socket) => {

  // join a room and tell everyone.
  socket.join('secretlol');
  io.to('secretlol').emit('message', {
    str: 'somebody joined secretlol',
  });

  // or you could broadcast...
  socket.broadcast.to('secretlol').emit('message', {
    str: 'someone else joined secretlol',
  });

});

Questions?

Made with Slides.com