Introduction of KeystoneJS
KeystoneJS is a generic content management framework, meaning that it can be used for developing a variety of web applications using Javascript. It is especially suitable for developing large-scale applications such as portals, forums, content management systems (CMS), e-commerce projects and RESTful Web services because of its modular architecture and clean separation of various functionality. KeystoneJS is a powerful Node.js content management system and web app framework built on express and mongoose. Keystone makes it easy to create sophisticated websites and apps and comes with a beautiful auto-generated Admin UI.
Why use KeystoneJS?
KeystoneJS provides a standardized set of components that allow for the fast and easy development of web applications that can be quickly developed, maintained and extended. KeystoneJS has a number of key features that make it worth using including:
- Modularity – Keystone will configure express – the de facto web server for node.js – for you and connect to your MongoDB database using Mongoose, which is the leading ODM package.
- Auto-generated Admin UI – Whether you use it while you’re building out your application, or in production as a database content management system, Keystone’s Admin UI will save you time and make managing your data easy.
- Session Management – Keystone comes ready out of the box with session management and authentication features, including automatic encryption for password fields.
- Email Sending – Keystone makes it easy to set up, preview and send template-based emails for your application. It also integrates with Mandrill.
- Form Processing – Want to validate a form, upload an image, and update your database with a single line? Keystone can do that, based on the data models you’ve already defined.
- Database Fields – IDs, Strings, Booleans, Dates, and Numbers are the building blocks of your database. Keystone builds on these with useful, real-world fields types like name, email, password, address, image and relationship fields.
Install the generator
npm install -g generator-keystone
Create a folder for your project
mkdir my-test-project
cd my-test-project
Run the new project generator
yo keystone
Run it in your command line like this:
node keystone
Project Structure
|--lib | Custom libraries and other code |--models | Your application's database models |--public | Static files (css, js, images, etc.) that are publicly available |--routes | |--api | | Your application's api controllers | |--views | | Your application's view controllers | |--index.js | | Initialises your application's routes and views | |--middleware.js | | Custom middleware for your routes |--templates | |--includes | | Common .jade includes go in here | |--layouts | | Base .jade layouts go in here | |--mixins | | Common .jade mixins go in here | |--views | | Your application's view templates |--updates | Data population and migration scripts |--package.json | Project configuration for npm |--web.js | Main script that starts your application
routes/views and templates/views directories as much as possible.Models
Before you can start your Keystone app, you’ll need some data models. We’re going to start with the User model, which is special – we need it so that Keystone can do authentication and session management. Create the following two files in the /models folder models/index.js
require('./users.js');
models/users.js
User model. It doesn’t need to export anything, but the model must be registered with Keystone.var keystone = require('keystone'),
Types = keystone.Field.Types;
var User = new keystone.List('User');
User.add({
name: { type: Types.Name, required: true, index: true },
email: { type: Types.Email, initial: true, required: true, index: true },
password: { type: Types.Password, initial: true },
canAccessKeystone: { type: Boolean, initial: true }
});
User.register();
Authentication and Session Management
For Keystone to provide authentication and session management to your application, it needs to know a few things (which we’ve now configured).
- The option
user modelmust be the name of the Model that Keystone should look in to find your users. If you use a different model name, be sure to set the option correctly. - If you want your application to support session management, set the
sessionoption to true. Loading sessions incurs a small overhead, so if your application doesn’t need sessions you can turn this off. - Keystone has built-in views for signing in and out. To enable them, set the
authoption to true. You can also implement custom signin and signout screens in your applications’ views. - Sessions are persisted using an encrypted cookie storing the user’s ID. Make sure you set the
cookie secretoption to a long, random string. - The user model must have a
canAccessKeystoneproperty (which can be a virtual method or a stored boolean) that says whether a user can access Keystone’s Admin UI or not. *Note* If you choose to use a virtual method setting the value in mongodb directly will not authenticate correctly. A virtual method is useful when the criteria for access is more complex. See Mongoose virtuals
Routes
Our first view controller is going to be very simple – just rendering a template. Create an routes/views/index.jsfile like this: routes/views/index.js
var keystone = require('keystone');
exports = module.exports = function(req, res) {
var view = new keystone.View(req, res);
view.render('index');
}
Templates
Now, for the template our route will render. The render method looks in he views directory specified in our web.js, which we set to /templates/view. First up, create templates/views/index.jade: templates/views/index.jade
extends ../layouts/base block content h1 Hello World
Common Route Middleware
routes/middleware.js file keeps your route index nice and clean. If your middleware file gets too big, it’s a good idea to restructure any significant functionality into custom modules in your projects /lib folder.Middleware functions
req– an express request objectres– an express response objectnext– the method to call when the middleware has finished running (including any internal callbacks)
Flash message support (no, not that flash)
infosuccesswarningerror
You can easily support other types of messages by updating your middleware and the .jade template that renders them (which we’ll get to below). To use flash messages in your route controllers, do this: req.flash('info', 'Some information!');
Public Assets
You’ll want to add your own css, javascript, images and other files to your project. In the examples above, we’re including /styles/site.min.css and /js/lib/jquery-1.10.2.min.js.
Keystone will serve any static assets you place in the public directory. This path is specified in web.js by the static option.
It will also automatically generate .css or compressed .min.css files when a corresponding .less file is found in the public folder, as specified in web.js by the less option. For more information on LESS, see lesscss.org.
Production vs. Development
Keystone applies different settings in production and development modes. The environment will default to development, so you should set the NODE_ENV environment variable to production on your production servers for better performance. Your app can detect which environment it is running in by calling keystone.get(‘env’). When you deploy your KeystoneJS app to production, be sure to set your ENV environment variable to production. You can do this by setting NODE_ENV=production in your .env file, which gets handled by dotenv.
Creating an admin user
/updates/0.0.1-admins.js with the following credentials:- email – user@keystonejs.com
- password – admin
1exports.create={2User:[3{'name.first':'Admin','name.last':'User',:'user@keystonejs.com',4password:'admin',isAdmin:true}5]6};
The KeystoneJS administration site
Start up our app using the node keystone.js command and open http://127.0.0.1:3000/keystone/signin in your browser. You should see the administration login page shown below.

Dynamically adding columns to Admin UI
One of the most useful features for looking at data in the admin interface is the ability to dynamically add columns that we are interested in without having to modify the definition of the model in code. The columns dropdown on the top right lists all the fields defined in our model. Columns that have been listed in the default columns option will appear with tick marks next to them. We can then pick any additional columns that we are interested in working with.

If a custom field was chosen, it will be added to the end of the displayed column headers. We can reset the list of displayed columns to the original state by using the ‘Reset to default’ option that will appear in the dropdown once one or more columns have been selected.
Disabling the Admin UI
Services
Google Analytics
ga property String |
Your Google Analytics Property
Will default to
process.env.GA_PROPERTY |
ga domain String |
Your Google Analytics Domain
Will default to
process.env.GA_DOMAIN |
Google Maps
keystone.set('google api key', 'your-browser-key');
keystone.set('google server api key', 'your-server-key');
keystone.set('default region', 'au'); // optional, will limit autocomplete results to Australia
Amazon S3
s3 config option to an object containing your configuration (see example below). Alternatively, set the S3_BUCKET,S3_KEYand S3_SECRET environment variable.keystone.set('s3 config', { bucket: 'my-bucket', key: 'my-key', secret: 'my-secret' });
Windows Azure Storage
azurefile config option to an object containing your configuration.keystone.set('azurefile config', { account: 'my storage account', key: 'secret api key' });
Cloudinary
cloudinary secure option to true.keystone.set('cloudinary config', { cloud_name: 'my-cloud', api_key: 'abc', api_secret: '123' });
// or
keystone.set('cloudinary config', 'cloudinary://api_key:api_secret@cloud_name' );
// optional, will prefix all built-in tags with 'keystone_'
keystone.set('cloudinary prefix', 'keystone');
// optional, will prefix each image public_id with [{prefix}]/{list.path}/{field.path}/
keystone.set('cloudinary folders', true);
// optional, will force cloudinary to serve images over https
keystone.set('cloudinary secure', true);
Embed.ly
embedly api key option.EMBEDLY_API_KEY environment variable if it is set.keystone.set('embedly api key', 'your-key');
Mandrill
mandrill api key and mandrill username options. These options will be default to the MANDRILL_API_KEY & MANDRILL_USERNAME environment variable’s if set.keystone.set('mandrill api key', 'your-key');
keystone.set('mandrill username', 'your-username');





