Skip to content

Latest commit

 

History

History
208 lines (135 loc) · 7.46 KB

EVENTS.md

File metadata and controls

208 lines (135 loc) · 7.46 KB

Core Events

Status

Stability: 2 - Unstable

The API is in the process of settling, but has not yet had sufficient real-world testing to be considered stable.

Backwards-compatibility will be maintained if reasonable.

Purpose

The instantiated sails object is a Node EventEmitter.

WARNING sails.on(*) events are for contributors to the core or developers building custom hooks.

Please do not use these events directly in your app. You have been warned!

Background

Events have been a feature of the Sails core since v0.9.

  • Developers needed an easier way to modify the Sails core for their needs. Hooks and events make this possible!
  • Events themselves originated as a feature to allow hooks to talk to each other during and after the app bootstrapping process.
  • For posterity, the original sails.on(*) event proposal: https://gist.github.com/mikermcneil/5898598

Best Practices

Although it can be tempting, it's really best not to add new events to sails in your app code. In general, consistent conventions, clarity, and simplicity are the best practice for developing apps, because it makes them easier to extend, and makes it easier for you to remember how everything works when you come back to it later (not to mention everyone else on your team!)

If you want to add/trigger events to monkeypatch your Sails core, it's best to do this by authoring a hook. More information will show up as we learn more about best practices around that process, but one thing we've definitely learned is that you're better off namespacing your events and firing them on a single object (sails), than emitting and listening on different objects. Why? Sometimes objects get deleted or copied, and this can make a big mess.

If you need a special event in your hook, you will want to namespace it. For instance, if I'm adding a hook called enforceRestfulSesssions that limits the actions that can be added to controllers to encourage code consistency, I might have a hook:enforceRestfulSesssions:checked event that fires when all of the controllers have been checked. This is so that other hooks that know about enforceRestfulSesssions can wait until it has finished its check before proceeding (whether it's just me, or other people on my team, or if I release my hook and it gets popular, other people in the Sails community).

In my hook's initialize method, I might have the following:

// Wait until all the middleware from this app's controllers have loaded
sails.after('hook:controllers:loaded', function () {

  // Do stuff
  // e.g. prevent any methods called `login`, `logout` or `signup`
  // since we've opted organizationally for using CRUD on a SessionController instead
  // .....code here........

  // When you're done, fire an event in
  sails.emit('hook:enforceRestfulSesssions:checked');

});

Reference

Lifecycle

lifted

Called after drawing the sailboat.

ready

Called when all hooks are loaded and the internal router is ready to handle requests. i.e. the HTTP hook listens for ready before binding its HTTP server.

lower

Called when sails.lower() is called. sails.lower() is called automatically when the process is halted.

router:before

Called before any of the app's configured static routes have been bound. i.e. a hook might listen to this event to bind some middleware.

router:after

Called after all of the app's configured static routes have been bound. i.e. a hook might listen to this event to bind a "shadow route" to a blueprint.

router:done

Called when all routes have been bound, including those originating from hooks (i.e. things listening for router:after.)

router:reset

Called when the router is flushed (i.e. all routes are unbound). The http hook (i.e. Express), and any other attached servers which maintain their own routes should listen for this event so they know to unbind their private routes.

Lift-time

router:bind

Called when a route is bound. This allows hooks to handle routes directly if they want to-

Should receive a single argument, "routeObj", which looks like:

{
  path: 'String',
  target: function theFnBoundtoTheRoute (req, res, next) {},
  verb: 'String',
  options: 'Object'
}
router:unbind

Called when a route is unbound.

Runtime

NOTE: these events should only be relied on by attached servers without their own routers, or when a hook implementation prefers to use the built-in Sails router.

The optimal behavior for the http hook implemented on Express, for instance, is to listen to router:bind from the built-in router and listen for the routes itself using app.use. On the other hand, in the sockets hook, Socket.io needs to use the router:request event to simulate a connect-style router since it can't bind dynamic routes ahead of time.

router:request

Called when a request is received by the Sails router. Should receive three arguments, req, res, and next.

router:request:500

Absolute last-resort handler for server errors. Called when a request encounters an error and isn't handled by other means. Should receive three arguments, err, req, and res.

router:request:404

Absolute last-resort handler for requests which don't match any routes. Called when a request doesn't match any routes (or shadow routes, including 404/slug handlers), and this case isn't handled by other means. Should receive two arguments, req, and res.

router:route

Called every time a request is routed. Compare with router:request- e.g.:

sails.router.bind('/foo/*', noop);
sails.router.bind('/foo/:bar', noop);
sails.router.bind('/foo/explicit', noop);

// Request to /foo/x will emit `router:request` only once, but `router:route` three times.

Usage

sails.on()

Fires your handler NEXT TIME the event is triggered and EVERY TIME AFTERWARD.

sails.on('hook:yourHookID:someEvent', function yourEventHandler ( /* a, b, c, ..., z */ ) {
  // your implementation
});

sails.once()

Fires your handler NEXT TIME the specified event is triggered, and then stop listening.

sails.once('hook:yourHookID:someEvent', function yourEventHandler ( /* a, b, c, ..., z */ ) {
  // your implementation
});

sails.after()

Fires your handler IF THE SPECIFIED EVENT HAS ALREADY BEEN TRIGGERED or WHEN IT IS TRIGGERED.

Kind of like jQuery's $(document).ready(), except document is whatever you want. Useful for checking whether some state has been achieved yet.

sails.after('hook:yourHookID:someEvent', function yourEventHandler ( /* a, b, c, ..., z */ ) {
  // your implementation
});

You can actually wait for several events using .after as well:

sails.after(['hook:yourHookID:someEvent', 'hook:someOtherHookID:someOtherEvent'], function yourEventHandler ( /* a, b, c, ..., z */ ) {
  // your implementation
});

FAQ

If you have a question that isn't covered here, please feel free to send a PR adding it to this section (even if you don't have the answer!)