Sails.js Web Framework
Sails.js is an MVC-based Node.js web framework designed for building custom, enterprise-grade applications, particularly those requiring real-time features using WebSockets. It aims to provide a Rails-like developer experience but with a data-oriented approach suitable for modern APIs. The current stable version is 1.5.17, with patch releases occurring periodically to address dependencies and minor fixes. Major version updates, like the transition to v1.0, introduced significant breaking changes, prioritizing developer experience over strict backward compatibility. Sails differentiates itself through its convention-over-configuration philosophy, automatic RESTful API generation, integrated ORM (Waterline) with multi-database support, and native Socket.io integration for real-time communication. It also embraced `async/await` syntax from v1.0 onwards, streamlining asynchronous code.
Common errors
-
TypeError: Cannot set headers after they are sent to the client
cause Attempting to send multiple HTTP responses for a single request, often due to improper `res.send()` or `res.json()` usage after another response has already been sent, or due to unhandled errors that implicitly send a default response.fixEnsure that each request handler (action, policy, middleware) sends only one response. Use `return` before `res.send()`, `res.json()`, `res.serverError()`, etc., to prevent further code execution after a response has been dispatched. Implement robust error handling. -
Error: An app failed to lift. (Usually means a hook threw an error)
cause A common startup error in Sails, indicating an issue during the application bootstrap or hook initialization phase. This can be due to misconfigured database connections, invalid model definitions, syntax errors in config files, or unhandled exceptions in bootstrap logic.fixCheck server logs for more specific error messages from individual hooks, models, or configurations. Verify database connection settings in `config/datastores.js` and model definitions for correctness. Review the `config/bootstrap.js` file for any problematic logic. Incrementally comment out hooks or custom logic to isolate the problematic component. -
E_UNIQUE: A uniqueness constraint was violated
cause Attempting to create or update a record with a value for an attribute that has been defined with a `unique: true` constraint, and that value already exists in the database.fixBefore creating or updating, perform a check to see if a record with the unique value already exists. Handle the `E_UNIQUE` error specifically in `try/catch` blocks or promise `.catch()` handlers, providing appropriate feedback to the user or logic to resolve the conflict.
Warnings
- breaking Upgrading to Sails v1.0 from any v0.x version involved significant breaking changes, including changes to configuration (especially datastores), model definitions (e.g., `autoPK` removed), and the results of `.create()`, `.update()`, and `.destroy()` methods. Many core hooks became direct dependencies.
- gotcha When programmatically lifting Sails applications, such as for testing, environment variables like `.sailsrc` settings are not automatically applied. Additionally, running multiple Sails app instances in the same process with globals enabled can lead to collisions.
- breaking Sails v1.0+ fully embraces `async/await` for asynchronous operations. While traditional `.exec()` with callbacks is still supported, mixing styles or neglecting error handling with promises (`.then().catch()`) can lead to unhandled rejections and instability.
- gotcha From v1.3.1, an update to the `machine-as-action` dependency included a reminder about escaping strings with dynamic data when injected into views or responses, indicating a potential XSS vulnerability if not handled correctly.
- deprecated The `sails.services` object, while still accessible, has been superseded by 'helpers' since Sails v1.0. The new 'Actions2' syntax for controllers also streamlines definition and validation.
Install
-
npm install sails -
yarn add sails -
pnpm add sails
Imports
- Sails (for programmatic use)
import Sails from 'sails';
const Sails = require('sails').constructor; - sails (global instance)
import sails from 'sails';
const sails = require('sails'); - Model access (e.g., User)
import { User } from '../api/models/User';const User = sails.models.user; // Or simply `User` if globals are enabled
Quickstart
```bash
# Install Sails CLI globally
npm install sails -g
# Create a new Sails project
sails new my-sails-app --no-template
cd my-sails-app
# Generate a simple User model
sails generate model User name:string email:string
# Generate a UserController
sails generate controller User --actions 'find,create'
# Lift the Sails application (start the server)
sails lift
# --- Example of programmatic interaction (after lifting) ---
# In a separate script, e.g., `test.js`:
# const Sails = require('sails').constructor;
# const sailsApp = new Sails();
#
# sailsApp.lift({ log: { level: 'warn' } }, async (err) => {
# if (err) {
# console.error('Error lifting Sails app:', err);
# return;
# }
# console.log('Sails app lifted successfully!');
#
# try {
# // Access a model and create a record
# const User = sailsApp.models.user; // Access the model instance
# const newUser = await User.create({
# name: 'Alice Smith',
# email: 'alice@example.com'
# }).fetch();
# console.log('Created user:', newUser);
#
# // Find all users
# const users = await User.find();
# console.log('All users:', users);
# } catch (queryErr) {
# console.error('Database query error:', queryErr);
# } finally {
# sailsApp.lower((lowerErr) => {
# if (lowerErr) console.error('Error lowering Sails app:', lowerErr);
# else console.log('Sails app lowered.');
# });
# }
# });
```