All Projects → shalvah → burns

shalvah / burns

Licence: other
Manage your application's events without writing spaghetti code

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to burns

Goes
Go Event Sourcing made easy
Stars: ✭ 144 (+67.44%)
Mutual labels:  events, event-driven
vcenter-connector
Extend vCenter with OpenFaaS
Stars: ✭ 29 (-66.28%)
Mutual labels:  events, event-driven
Noel
A universal, human-centric, replayable javascript event emitter.
Stars: ✭ 158 (+83.72%)
Mutual labels:  events, event-driven
Remit
RabbitMQ-backed microservices supporting RPC, pubsub, automatic service discovery and scaling with no code changes.
Stars: ✭ 24 (-72.09%)
Mutual labels:  events, event-driven
EventEmitter
Simple EventEmitter with multiple listeners
Stars: ✭ 19 (-77.91%)
Mutual labels:  events, event-driven
Eventing
Open source specification and implementation of Knative event binding and delivery
Stars: ✭ 980 (+1039.53%)
Mutual labels:  events, event-driven
Watermill
Building event-driven applications the easy way in Go.
Stars: ✭ 3,504 (+3974.42%)
Mutual labels:  events, event-driven
Fluentmediator
🔀 FluentMediator is an unobtrusive library that allows developers to build custom pipelines for Commands, Queries and Events.
Stars: ✭ 128 (+48.84%)
Mutual labels:  event-driven, event-handlers
tardis
Event sourcing toolkit
Stars: ✭ 35 (-59.3%)
Mutual labels:  events, event-driven
ng2-events
Supercharge your Angular2+ event handling
Stars: ✭ 17 (-80.23%)
Mutual labels:  events, event-handlers
Message Io
Event-driven message library for building network applications easy and fast.
Stars: ✭ 321 (+273.26%)
Mutual labels:  events, event-driven
kstreams-des-demo
Kafka Streams demo project containing Derivative Events, the Processor Api and Wall-clock examples
Stars: ✭ 24 (-72.09%)
Mutual labels:  events, event-driven
wishbone
A Python framework to build composable event pipeline servers with minimal effort.
Stars: ✭ 42 (-51.16%)
Mutual labels:  events, event-driven
Observable
minimalist event system for Python
Stars: ✭ 66 (-23.26%)
Mutual labels:  events, event-handlers
cute
An event-centric publisher/subscribe model for objects inspired by the Qt framework
Stars: ✭ 37 (-56.98%)
Mutual labels:  events, event-driven
Event Driven Spring Boot
Example Application to demo various flavours of handling domain events in Spring Boot
Stars: ✭ 194 (+125.58%)
Mutual labels:  events, event-driven
evon
Fast and versatile event dispatcher code generator for Golang
Stars: ✭ 15 (-82.56%)
Mutual labels:  events, event-driven
event-dispatcher
💥 Best events support (symfony/event-dispatcher) to Nette Framework (@nette)
Stars: ✭ 23 (-73.26%)
Mutual labels:  events, listeners
eventcatalog
Discover, Explore and Document your Event Driven Architectures powered by Markdown.
Stars: ✭ 392 (+355.81%)
Mutual labels:  events, event-driven
rel-events
The relevant React Events Library.
Stars: ✭ 20 (-76.74%)
Mutual labels:  events

Burns


Excellent

npm version Build Status Dependabot Status npm

Burns is a lightweight (no dependencies!) Node.js module for managing application events elegantly. Define your events and handlers in one place and dispatch them when you need to.

Inspired by Laravel's events and broadcasting systems.

What you get

  • Easy visibility of all application events
  • Default handler to catch generic events
  • Attaching event handlers at multiple places
  • Asynchronous handling of events
  • Inbuilt event broadcasting

Installation

npm install burns

How to use

const burns = require('burns');

Define an event handler:

// handlers/order.js

function sendOrderShippedEmail(data)
{
    mailer.sendEmail(`Hi ${data.userName}, Your order ${data.orderId} has been shipped`);
}

Register the event and attach the handler:

let { sendOrderShippedEmail } = require('./handlers/order');
burns.registerEvents({
  orderShipped: sendOrderShippedEmail
});

Dispatch the event when you're ready! 🚀

burns.dispatch('orderShipped', {
    orderId: order.id,
    userName: user.name
});

Registering events

Register events by calling registerEvents with a single object. The names of your events should be the keys of this object and their handlers the values:

burns.registerEvents({
  newPurchase: sendInvoice,
  orderShipped: notifyUser
});

You can also attach multiple handlers to a single event:

burns.registerEvents({
  userSignUp: [
    userListener.sendEmail,
    userListener.congratulateReferrer
  ]
})

Burns allows you to register events at multiple locations. This means that for a large application, you can have each application component define its own events and handlers by calling registerEvents wherever it needs to.

Defining handlers

A handler is a function that responds to an event. A handler takes a single parameter, the event payload which you pass when dispatching the event:

function sendInvoice(data)
{
    let invoice = createInvoice(data.order, data.user);
    mailer.sendEmail('Here is your order invoice', invoice);
}

burns.registerEvents({
  newPurchase: sendInvoice,
});

// this will call sendInvoice with data = {}
burns.dispatch('newPurchase');

// this will call sendInvoice with data containing order and user
burns.dispatch('newPurchase', {
    order: getOrder(),
    user: findUser()
});

Stopping event propagation

Suppose you're running a subscription service (like Netflix) where you bill users every month. Your app can fire a newBillingPeriod event and perform multiple actions when this event is fired: charge the customer's card, extend their subscription, send them a invoice. Burns allows you to register multiple handlers for the event, and will call them in the order in which they were registered:

burns.registerEvents({
  newBillingPeriod: [
      chargeCustomerCard,
      extendCustomerSubscription,
      sendCustomerInvoice,
   ]
})

If the process of charging the customer's card fails, you probably wouldn't want to go through with the other actions. In such a situation, you can prevent the subsequent handlers from being called by returning false from the current handler:

function chargeCustomerCard(customer) {
  if (!PaymentProcessor.chargeCard(customer)) {
      // bonus: dispatch a 'chargeCardFailed` event. Cool, huh?
    burns.dispatch('chargeCardFailed', customer);
    return false;
  }

}

Using a default handler

You may specify a defaultHandler. Burns will pass a dispatched event to this handler if no handlers are registered for it:

function handleEverything (data) {}

burns.configure({
    defaultHandler: handleEverything
});

// this will call handleEverything
burns.dispatch('unregisteredEvent', somePayload);

Dispatching events

To dispatch an event, call dispatch with the name of the event:

burns.dispatch('postLiked');

You may also pass in a payload containing data to be transmitted with the event:

burns.dispatch('postLiked', {
    postId: 69,
    likedBy: 42,
});

This object will be passed as an argument to the handler.

Broadcasting events

Supposing you have an orderStatusUpdated event that is fired when the status of an order is updated, and you wish to update the order status on your frontend in realtime. Burns handles this for you via event broadcasting.

Configuring broadcasting

You'll need to specify a broadcaster. For now, broadcasting is only supported to the console log (broadcaster: 'log') and Pusher (broadcaster: 'pusher'). The default broadcaster is log, which will log all broadcasts to the Node console. (You can disable broadcasting by setting broadcaster: null.)

If you're broadcasting with Pusher, pass in your credentials as a pusher object:

burns.configure({
  broadcaster: 'pusher',
  pusher: {
    appId: 'APP_ID',
    key: 'APP_KEY',
    secret: 'SECRET_KEY',
    cluster: 'CLUSTER',
  }
})

To use the pusher broadcaster, you need to install the Pusher Node.js SDK: npm install pusher

Broadcasting an event

Then register the orderStatusUpdated using the "advanced" configuration format:

burns.registerEvents({
  orderStatusUpdated: {
      handlers: [
          notifyUser
      ],
      broadcastOn: 'orderStatusUpdates' // or an array of channels
  }
});

The broadcastOn key specifies the name of the channel on which the event will be broadcast. It can be a string or a function that takes in the event payload and returns a channel name.

Now when you call

burns.dispatch('orderStatusUpdated', order);

Burns will automatically publish a message on the channel orderStatusUpdates with the order object as the payload. All that's left is for you to listen for this event on the frontend.

If you'd like to exclude the client that triggered the event from receiving the broadcast, you can pass in an object as the third parameter to dispatch(). The 'exclude' key should contain the socket ID of the client to exclude:

burns.dispatch('orderStatusUpdated', order, { exclude: socketId });

Conditional broadcasting

You can also have conditional broadcasting by using the broadcastIf property.

burns.registerEvents({
  orderStatusUpdated: {
      handlers: [
          notifyUser
      ],
      broadcastOn: 'orderStatusUpdates',
      broadcastIf: process.env.NODE_ENV === 'production'
  }
});

You may specify a function that takes the event payload and should return true or false:

({
    broadcastIf: (data) => data.user.notifications.enabled === true,
    // your function can return a promise too. Burns will await the result
    // broadcastIf: (data) => data.user.getSettings()
    //   .then(settings => settings.notifications.enabled === true),
})

`

But Node already supports events natively!

Yes, and that's a great thing for handling events at lower levels in your code base (for instance, on open of a file, on data of a stream). When dealing with events at a higher level (such as a new user signing up), Burns is perfect for helping you keep your code clean and organized.

Asynchronous vs. Synchronous

Unlike Node.js' inbuilt events system, Burns calls your event handlers asynchronously in the order in which they were registered. This means that the functions are queued behind whatever I/O event callbacks that are already in the event queue, thus enabling you to send a response to your user immediately, while your event gets handled in the background.

This also means that if you dispatch one event from a handler for another event, all of the original event's handlers will be executed first, before moving on to those for the newly-dispatched event.

Like it?

Star and share, and give me a shout out on Twitter

Contributing

If you have an bugfix, idea or feature you'd like to implement, you're welcome to send in a PR!

(Requires Node v8 or above)

  • Clone the repo
git clone https://github.com/shalvah/burns.git
  • Create a branch for your fix/feature:
git checkout -b my-patch
  • Write your code. Add tests too, if you know how. If you're not sure how, just send in the PR anyway.

  • Make sure all tests are passing

npm run test
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].