Excellent. The crew is organized, but our communication methods are antiquated. Sending a message to another ship requires a fast sloop and a fair wind. What if we could send messages instantly, as if by magic? It’s time to install the ship’s most advanced piece of equipment.
Part 6: Instant Dispatches (Real-time with WebSockets)
- Current Rank: Navigator
- Objective: To master the signature feature of Sails.js by upgrading your application with a real-time WebSocket layer for instantaneous, two-way communication.
The Captain’s Briefing (Background and Theory)
Navigator, thus far all our communication has followed the “message in a bottle” protocol (standard HTTP). We send a request from our browser, and some time later, the server sends a response back. The server can never speak first. If a new treasure is discovered somewhere in the world, our ship won’t know about it until we manually ask for an update by refreshing the page.
This changes today. We are installing a Magical Telegraph, a technology known in other worlds as WebSockets.
A WebSocket isn’t a single message; it’s an open, persistent, two-way communications channel between the browser and your Sails server. It’s like having a direct, magical link. Your server can now push information to the browser at any time, without being asked. This is the foundation of all modern real-time features: live chats, notifications, activity feeds, and collaborative applications.
Sails.js and Socket.io: The Telegraph Machine
Setting up WebSockets from scratch is a complex feat of engineering. Thankfully, Sails comes with a masterfully built telegraph machine called Socket.io integrated directly into its core. Sails provides a set of simple, elegant commands to manage this powerful technology.
Subscribing to a Channel (The Room)
The key to managing real-time communication is organization. You don’t want every message going to every person. You create channels, or “rooms.” A socket (a single browser connection) can be made to join a room.
sails.sockets.join(req, 'some-room-name');
This command tells Sails, “The browser that made this request is now listening to the ‘some-room-name’ channel.”
Broadcasting a Message
Once sockets have joined a room, you can send a message specifically to that room from your server-side code:
sails.sockets.broadcast('some-room-name', 'eventName', { some: 'data' });
This sends a message with the name eventName
and a data payload to every single socket listening to that channel.
Blueprint Pub/Sub: The Auto-Magic
Here is where Sails ascends from useful to truly magical. This concept is called Publish/Subscribe, or “Pub/Sub.” When you use the Blueprint API from a browser over a socket connection, Sails automatically manages the room subscriptions for you!
- When you make a request like
io.socket.get('/treasure', ...)
, Sails sees this and thinks, “Aha! This browser is interested in treasure.” It automatically subscribes that socket to notifications about theTreasure
model. - Later, if anyone in the world (via another browser or a script) creates, updates, or destroys a treasure, the Blueprint API will publish an event.
- Sails automatically broadcasts this event to all subscribed sockets.
This means you get real-time model updates for free, just by using the API you already know over a socket connection.
Listening on the Client
How does the browser listen for these incoming telegraph messages? Sails provides a client-side JavaScript file, sails.io.js
, which is included for you automatically. It gives you a global io
object. The most important function is io.socket.on()
:
// On the front-end, in a <script> tag
io.socket.on('eventName', function (data) {
// This code runs when a message called 'eventName' arrives
console.log('The server sent a message!', data);
});
Key Concepts Checklist
WebSockets
: A technology for persistent, two-way communication between server and client.Socket.io
: The library Sails uses to manage WebSockets.sails.io.js
: The client-side JavaScript library for connecting to the Sails socket server.Subscription
: The act of putting a socket into a “room” to listen for specific messages.Blueprint Pub/Sub
: The powerful “publish/subscribe” feature that automatically broadcasts model changes to subscribed sockets.io.socket.get()
: Making aGET
request over a socket instead of standard HTTP.io.socket.on()
: The client-side listener for incoming socket events.
Mission Log: Quest - “The Live Treasure Tracker”
We will build a simple dashboard that displays a list of all treasures. Then, using the magic of WebSockets, we will make it so that when a new treasure is created anywhere, it instantly appears on our dashboard page without a refresh.
Task 1: Build the Dashboard Page
- Create a new controller with the generator:
sails generate controller TreasureController
Open
api/controllers/TreasureController.js
and add an action to just show a page:module.exports = { trackerPage: function (req, res) { return res.view('pages/tracker'); } };
Create the corresponding view file at
views/pages/tracker.ejs
:<h1>Live Treasure Fleet Tracker</h1> <p>This list will update in real-time as new treasures are added to the database.</p> <ul id="treasure-list"> <!-- Treasures will be added here by our script --> </ul> <!-- Add a script block at the bottom for our client-side code --> <script src="/js/dependencies/sails.io.js"></script> <script type="text/javascript"> // We will fill this in next </script>
- Add the route in
config/routes.js
:'GET /tracker': 'TreasureController.trackerPage'
- Create a new controller with the generator:
Task 2: Write the Client-Side Telegraph Operator
In your
views/pages/tracker.ejs
file, replace the empty script body with this JavaScript code. Read the comments carefully to understand the steps.const treasureList = document.getElementById('treasure-list'); // Helper function to add a treasure to our <ul> list function addTreasureToList(treasure) { const newListItem = document.createElement('li'); newListItem.textContent = `${treasure.name} (Value: ${treasure.value} doubloons)`; treasureList.appendChild(newListItem); } // --- Step 1: Get the initial list of treasures when the page loads --- // We use io.socket.get() to make a request over a WebSocket connection. // This automatically subscribes this browser to all "treasure" model events! io.socket.get('/treasure', function (treasures, JWR) { if (JWR.statusCode === 200) { treasures.forEach(addTreasureToList); } else { console.error('Could not fetch treasures from server'); } }); // --- Step 2: Listen for real-time updates from the server --- // The event name 'treasure' is automatically chosen by Sails based on the model name. io.socket.on('treasure', function (event) { // The 'event' object tells us what happened. // We only care about newly created treasures for this quest. if (event.verb === 'created') { const newTreasure = event.data; addTreasureToList(newTreasure); console.log('A new treasure appeared by magic!', newTreasure); } });
Task 3: Witness the Magic
- Restart your server with
sails lift
. - Open Browser Tab 1: Navigate to
http://localhost:1337/tracker
. You should see a list of any treasures you created in Module 4. - Open Browser Tab 2: We need to create a new treasure. Use the Blueprint API
create
route. Assuming you have a captain withid
of1
, navigate to this URL:http://localhost:1337/treasure/create?name=The Kraken's Eye&value=99000&owner=1
- As soon as you press Enter in Tab 2, look at Tab 1. Instantly, without refreshing the page, “The Kraken’s Eye” will appear at the bottom of the list. You have just witnessed a real-time WebSocket push from the server!
- Restart your server with
Mission Debrief (Review & Outcomes)
Incredible! The magical telegraph is online. You have achieved one of the most powerful and sought-after features in modern web development.
You created a page that subscribed itself to model updates just by fetching its initial data over a socket. When another user (you, in another tab) modified the data, the Sails backend published an event, which was instantly pushed to your tracker page. Your client-side JavaScript caught the event and updated the display. This entire complex workflow was handled with just a few lines of code, demonstrating the immense power and productivity of the Sails.js framework.
Rewards & Promotion
- +250 Doubloons
- Achievement Unlocked: You have bent the laws of space and time, sending messages instantly from server to client. You are a master of real-time communication.
- Badge Earned:
Socket Sorcerer
✨
- Badge Earned:
- Promotion to: Quartermaster
As Quartermaster, you are a master of the ship’s stores (Models) and now its communications (Sockets). You hold a position of immense trust and authority. Your next duty is to ensure the security of the ship.