november-cli
                                
                                 november-cli copied to clipboard
                                
                                    november-cli copied to clipboard
                            
                            
                            
                        ❄️ Generate a Node.js API for your Ember.js app

November helps you generate a simple Node.js API tailored for Ember.js apps, with the help of Express and Sequelize.
Installation
$ npm install -g november-cli
Get started
$ november new my-app
This will create a new project with the following structure:
├── app
│   ├── actions
│   ├── controllers
│   ├── middleware
│   ├── models
│   ├── router.js
│
├── config
│   ├── config.json
│
├── lib
├── migrations
├── node_modules
├── public
├── server.js
├── test
By default, MySQL is used as a database, but you can use any relational database supported by Sequelize by changing the values in config/config.json.
To run the app, run npm start (or just nodemon if you have it installed) in your app’s directory and visit localhost:9000.
In your Ember.js app
Make sure you change the host in your Ember.js adapter file so that it can communicate with November:
# In your ember project folder
$ ember generate adapter
// app/adapters/application.js
import DS from "ember-data";
export default DS.RESTAdapter.reopen({ 
  host: 'http://localhost:9000'
});
Models
$ november generate model user
This generates:
- A model file (app/models/user.js) for the user, which will determine the structure of the database table
- Routes in app/router.jsfor creating, reading, updating and deleting users (based on the conventions of Ember Data). Feel free to remove the actions you don't need.
- Controller files, which hook up the routes to database actions:
- app/controllers/user/add.js
- app/controllers/user/list.js
- app/controllers/user/load.js
- app/controllers/user/update.js
- app/controllers/user/remove.js
 
With the app and your local database running in the background, visit localhost:9000/users, and you should see:
{
  "users": []
}
The table users has automatically been created in your database.
Actions
Actions are for API endpoints which are not specifically tied to any model.
$ november generate action login
This generates:
- An action file (app/actions/login.js)
- A route in app/router.js(POSTby default)
Render()
The render()-method in your controllers is used for rendering both your models and your error messages. It takes a single argument.
Rendering models
If you pass a valid sequelize model to render(), it will generate that model according to the JSON API conventions used by Ember Data.
The most basic usage:
render(<your-sequelize-model>);
...which can also be typed like this:
render({
  model: <your-sequelize-model> 
});
returns:
{
  "user": {
    <...>
  }
}
If your sequelize model includes associated models, they are sideloaded by default:
{
  "user": {
    <...>
    "tweets": [1, 5]
  },
  "tweets": [
    <...>
  ]
}
However, you can also specify if you want some (or all) associations to be embedded instead.
Here we specify that we want the tweets-association to be embedded. If we wanted all associations to be embedded, we would set embedded: true
render({
  model: <your-sequelize-model>,
  embedded: ['tweets']
});
... which returns:
{
  "user": {
    <...>
    "tweets": [
      {
        id: 1,
        <...>
      },
      {
        id: 5,
        <...>
      }
    ]
  }
}
Rendering errors
Controllers generated by November rely heavily on promises. If they catch an error, they call render(error).
Let's say we accidentally search for a field (name) which doesn't exist in our database table:
// app/controllers/user/list.js
req.models.user
.findAll({
  where: {
    name: "Bob"
  }
})
.then(function(users) {
  // Not gonna happen
})
.catch(function(err) {
  render(err);
});
An error will be catched and render(err) will return this JSON to the client:
{
  "error": {
    "code": 500,
    "message": "Could not load users"
  }
}
... while still showing a more descriptive error to the developer in the console so that you can locate the problem:

You can also render your own exceptions to the user, by throwing a string with the error message or an array where the first element is the error code and the second is the error message:
// app/controllers/user/update.js
req.models.user.find({
  where: {
    username: req.params.username
  }
})
.then(function(user) {
  if (user.id !== req.user) {
    throw [403, "You are not allowed to edit this user!"]
  }
  return user.save();
})
.then(function(user) {
  // Not gonna happen
})
.catch(function(err) {
  render(err);
});
...what the client will see:
{
  "error": {
    "code": 403,
    "message": "You are not allowed to edit this user!"
  }
}
Todos
TDD is not really my thing, but it would be nice to get some automatic Mocha tests when you generate new models. :)
Contact
If you have any questions, feel free to ping me on Twitter or just open an issue!