Git Product home page Git Product logo

expresse's Introduction

AssetBundleCompiler logo

ExpreSSE npm version license Travis Build npm total downloads

ExpreSSE is a set of middlewares - with a simple and elegant API - for working with Server-Sent Events (SSE) in Express. SSE is a simple unidirectional protocol that lets an HTTP server push messages to a client that uses window.EventSource. It's HTTP long-polling, without polling!

From the MDN:

Traditionally, a web page has to send a request to the server to receive new data; that is, the page requests data from the server. With server-sent events, it's possible for a server to send new data to a web page at any time, by pushing messages to the web page.



๐Ÿ“ฆ Installation & Usage

Requirements:

  • Node.js 5+ because ExpreSSE is transpiled down to ES 6 ;
  • Express 4

Install it via the npm registry:

yarn add @toverux/expresse

TypeScript users: the library as distributed on npm already contains type definitions for TypeScript. โœจ

sse() middleware

Import the middleware
  • Using ES 2015 imports:

    ISseResponse is a TypeScript interface. Don't try to import it when using JavaScript.

    import { ISseResponse, sse } from '@toverux/expresse';
    
    // named export { sse } is also exported as { default }:
    import sse from '@toverux/expresse';
  • Using CommonJS:

    const { sse } = require('@toverux/expresse');
Available configuration options
interface ISseMiddlewareOptions {
    /**
     * Serializer function applied on all messages' data field (except when you direclty pass a Buffer).
     * SSE comments are not serialized using this function.
     *
     * @default JSON.stringify
     */
    serializer?: (value: any) => string|Buffer;

    /**
     * Determines the interval, in milliseconds, between keep-alive packets (neutral SSE comments).
     *
     * @default 5000
     */
    keepAliveInterval?: number;
}

โžก๏ธ Read more about serializer


Usage example (remove ISseResponse when not using TypeScript):

// somewhere in your module
router.get('/events', sse(/* options */), (req, res: ISseResponse) => {
    let messageId = parseInt(req.header('Last-Event-ID'), 10) || 0;
    
    someModule.on('someEvent', (event) => {
        //=> Data messages (no event name, but defaults to 'message' in the browser).
        res.sse.data(event);
        //=> Named event + data (data is mandatory)
        res.sse.event('someEvent', event);
        //=> Comment, not interpreted by EventSource on the browser - useful for debugging/self-documenting purposes.
        res.sse.comment('debug: someModule emitted someEvent!');
        //=> In data() and event() you can also pass an ID - useful for replay with Last-Event-ID header.
        res.sse.data(event, (messageId++).toString());
    });
    
    // (not recommended) to force the end of the connection, you can still use res.end()
    // beware that the specification does not support server-side close, so this will result in an error in EventSource.
    // prefer sending a normal event that asks the client to call EventSource#close() itself to gracefully terminate.
    someModule.on('someFinishEvent', () => res.end());
});

sseHub() middleware

This one is very useful for pushing the same messages to multiples users at a time, so they share the same "stream".

It is based on the sse() middleware, meaning that you can still use res.sse.* functions, their behavior don't change. For broadcasting to the users that have subscribed to the stream (meaning that they've made the request to the endpoint), use the req.sse.broadcast.* functions, that are exactly the same as their 1-to-1 variant.

Import the middleware
  • Using ES 2015 imports:

    ISseHubResponse is a TypeScript interface. Don't try to import it when using JavaScript.

    import { Hub, ISseHubResponse, sseHub } from '@toverux/expresse';
  • Using CommonJS:

    const { Hub, sseHub } = require('@toverux/expresse');
Available configuration options

The options are the same from the sse() middleware (see above), plus another, hub:

interface ISseHubMiddlewareOptions extends ISseMiddlewareOptions {
    /**
     * You can pass a Hub instance for controlling the stream outside of the middleware.
     * Otherwise, a Hub is automatically created.
     * 
     * @default Hub
     */
    hub: Hub;
}

First usage example - where the client has control on the hub (remove ISseHubResponse when not using TypeScript):

// somewhere in your module
router.get('/events', sseHub(/* options */), (req, res: ISseHubResponse) => {
    //=> The 1-to-1 functions are still there
    res.sse.event('welcome', 'Welcome to you!');
    
    //=> But we also get a `broadcast` property with the same functions inside.
    //   Everyone that have hit /events will get this message - including the sender!
    res.sse.broadcast.event('newcomer', 'someone just hit the /events endpoint');
});

More common usage example - where the Hub is deported outside of the middleware:

const hub = new Hub();

someModule.on('someEvent', (event) => {
    //=> All the functions you're now used to are still there, data(), event() and comment().
    hub.event('someEvent', event);
});

router.get('/events', sseHub({ hub }), (req, res: ISseHubResponse) => {
    //=> The 1-to-1 functions are still there
    res.sse.event('welcome', 'Welcome! You\'ll now receive realtime events like everyone else');
});

๐Ÿ’ก Notes

About browser support

The W3C standard client for Server-Sent events is EventSource. Unfortunately, it is not yet implemented in Internet Explorer or Microsoft Edge.

You may want to use a polyfill on the client side if your application targets those browsers.

Chrome Edge Firefox Opera Safari
EventSource Support 6 No 6 Yes 5

Using a serializer for messages' data fields

When sending a message, the data field is serialized using JSON.stringify. You can override that default serializer to use your own format.

The serializer must be compatible with the signature (value: any) => string|Buffer;.

For example, to format data using the toString() format of the value, you can use the String() constructor:

app.get('/events', sse({ serializer: String }), yourMiddleware);

// or, less optimized:
app.get('/events', sse({ serializer: data => data.toString() }), yourMiddleware);

expresse's People

Contributors

fklingler avatar toverux avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.