1.8.4 • Published 7 years ago

gluon v1.8.4

Weekly downloads
2
License
MIT
Repository
github
Last release
7 years ago

npm.io

Gluon

We can call gluon a project boss. Simply manages routes, decides which route should go first, also manages models and database connection. With gluon, project development became so much easier..

installation

add dependency gluon to dependencies or type console

npm install gluon --save

basic usage

const gluon = require('gluon');
const app = gluon();

app.listen(80);

use with external app

const gluon = require('gluon');
const express = require('express');

const app = express();
gluon({ app });

app.listen(80);

using cwd + sub location. (Note if you make your project into src directory, you need this)

const gluon = require('gluon');
const app = gluon({dir: 'src/'}); // app.js located as cwd/src/app.js

app.listen(80);

routing mechanism

create a directory that called by routes

routes/home.js

const gluon = require('gluon');
const router = gluon.router();

router.get('/', (req, res) => {
  res.send("ok");
});

module.exports = router;

app.js

const gluon = require('gluon');
const app = gluon({dir: 'src/'}); // app.js located as cwd/src/app.js

// nothing required just works
app.listen(80);

try to connect http://localhost:80/home

sub-routing and index

create a directory that called by routes

routes/home.js

const gluon = require('gluon');
const router = gluon.router();

router.get('/', (req, res) => {
  res.send("ok");
});

module.exports = router;

routes/sub/index.js

const gluon = require('gluon');
const router = gluon.router();

router.get('/', (req, res) => {
  res.send("sub");
});

module.exports = router;

routes/sub/home.js

const gluon = require('gluon');
const router = gluon.router();

router.get('/', (req, res) => {
  res.send("sub-> home");
});

module.exports = router;

app.js

const gluon = require('gluon');
const app = gluon({dir: 'src/'}); // app.js located as cwd/src/app.js

// nothing required just works
app.listen(80);

try to connect these

  • http://localhost:80/home -> "ok"
  • http://localhost:80/sub -> "sub"
  • http://localhost:80/sub/home -> "sub-> home"

Note: Gluon has order mechanism that always index is last in own group. Example:

  • Next most powered group ordered by alphabet A/B/C A/B/C.js
  • Next most powered group and index A/B A/B/index.js
  • index / index.js

database and models

Gluon uses sequelize to communicate with database. But first you must create config folder in your cwd. For example your cwd is /root/myproject/, and your project files in /root/myproject/src create config in /root/myproject/config and don't forget to add dir option to gluon's first parameter.

Note: These modules requires sequelize and config please install before using it

you can create a json file that called by default.json

default.json

{
  "database": {
    "dialect": "mysql",
    "host": "your host address",
    "user": "database user name",
    "database": "database name",
    "password": "database password"
  }
}

now create a folder in src folder that called by models

models/user.js

const Sequelize = require('sequelize');
const db = require('gluon/db');

module.exports = db.define('User', {
  account: {
    type: Sequelize.STRING(32),
    allowNull: false,
    unique: true,
    validate: {
      isAlpha: true
    }
  },

  password: {
    type: Sequelize.STRING(32),
    allowNull: false,
    validate: {
      is: /^[a-f0-9]{32}$/
    }
  },

}, {
  freezeTableName: true,
  paranoid: true
});

everything is ready, start the project. gluon will connect db automaticly and load your models immediately. use your models in router

routes/user.js

const gluon = require('gluon');
const router = gluon.router();
const user = require('../models/user');

router.get('/', (req, res) => {
    user.all().then((data) => res.json(data));
});

module.exports = router;

Other awesome features

Generic option (default: true)

if you set generic option, you get plenty of new response types.

app.use((req, res) => {
    res.ok("ok :)");
});
  • ok Everything is OK 200 (text or json)
  • notFound Can't find user or something 404 (info) {error: true, info}
  • badRequest You made wrong request 400 (requiredFields) {error: true, requiredFields}
  • validation Your request didn't passed the validation 400 (type, fields) {error: true, type, fields}
  • unauthorized You are trying to use service without authorization 401 (info) {error: true, info}
  • redirectRequest Redirects a request to another one, like use POST please (info) {error: true, info}
  • unknown Bad Error 500 (info) {error: true, info}
  • database Database error (if caused by validation then it automaticly calls) 500 (err) {error: true, info: 'Database triggered an error. Please check your request. If there is no problem then contact with service provider.'}
  • expiredToken Use when a token expires 408 (info) {error: true, info}

Ready option and Before option

use when you need to wait all gluon initial job. Its very handy option

const gluon = require('gluon');
const app = gluon({
    dir: 'src/',
    before: (app) => {
        app.use(require('compression')());
    },
    ready: (app) => {
        app.use((err, req, res, next) => {
            res.send("something wrong");
        });
    }
});

app.listen(80);

Gluon request body controller

It helps you when you need control body. Lets check examples

Note: Gluon request body controller requires generic=true

routes/user.js

const gluon = require('gluon');
const control = require('gluon/control');
const router = gluon.router();
const user = require('../models/user');

// just give model
router.get('/', control(user), (req, res) => {
    user.all().then((data) => res.json(data));
});


// or give an array
router.get('/other', control(['account', 'password']), (req, res) => {
    
});

// if you don't want to control id
router.get('/', control(user, false), (req, res) => {
    user.all().then((data) => res.json(data));
});


module.exports = router;

If request cannot pass body controller, it send badRequest.

Gluon generator

If you bored to create CRUD you can use gluon generator.

Note: This generator requires js-md5 please install before using it. With this you don't need to serialize password field. it does automaticly.

Warning: Before generator you must definitely do authentication.

supported routes

GET /
GET /all
GET /count
POST /all (filter)
POST /count (filter)
GET /:id
DELETE /:id
POST / (create new model)
PATCH /:id (update exiting model)

Example

routes/user.js

const gluon = require('gluon');
const generator = require('gluon/generator');
const router = gluon.router();
const user = require('../models/user');

generator(router, user);

module.exports = router;

Gluon logger

Starting from 1.1.0 gluon no longer uses ezlogger, we suggest to use gluon/logger.

Options

These are default values of options, you can change them using by logger.set( ) or you can install config module and create logger object (example 2)

{
  dir: './logs',
  level: 'DEBUG',
  fileFormat: 'log.{date}.txt',
  dateFormat: '{year}/{month p 2}/{day p 2}',
  fileDateFormat: '{year}.{month p 2}.{day p 2}',
  timeFormat: '{hour p 2}:{minute p 2}:{second p 2}',
  type: 'full',
  full: '{date} {time} {type} {file}:{line} {message}',
  exceptDate: '{time} {type} {file}:{line} {message}',
  simple: '{type} {message}',
  withFile: '{type} {file}:{info} {message}',
  request: '[{req.method}] {coloredStatus} {time} {req.headers.host}{req.url} from {req.ip}'
}

Create new logging type

const logger = require('gluon/logger');
logger.set('myOwnLoggerType', '{time} {file}:{line} {type} {message}');
logger.set('type', 'myOwnLoggerType');

Example

app.js

const gluon = require('gluon');
const logger = require('gluon/logger')
logger.set('type', 'full'); // logs everything.. default value: full
logger.set('dir', './logs/'); // cwd/logs

const app = gluon({log: true}); // log route actions too
app.listen(80);
logger.log('server started to listen at 80');

routes/home.js

const gluon = require('gluon');
const logger = require('gluon/logger');
const router = gluon.router();


module.exports = router;

Example 2: with config

Note: You must install config first. npm install config --save

app.js

const gluon = require('gluon');
const logger = require('gluon/logger');

const app = gluon();
app.listen(80);
logger.log('server started to listen at 80');

routes/home.js

const gluon = require('gluon');
const logger = require('gluon/logger');
const router = gluon.router();


module.exports = router;

config/default.json

{
    "logger": {
        "level": "LOG",
        "type": "myOwn",
        "myOwn": "{type} {file}:{line} {message}"
    }
}

Gluon defaults by config

config/default.json

{
    "gluon": {
        "generic": "false", // don't use generic system
        "log": "false", // don't log requests
        "dir": "./src" // where is my app.js from cwd
    }
}

Direct listen from code or config

Note: if PORT is given by environment then this port is not will be evaluated

config/default.json

{
    "gluon": {
        "listen": 80 
        // or
        "listen": {
            "ip": "1.2.3.4",
            "port": 80
        }
    }
}

or

const gluon = require('gluon');
const app = gluon({
    listen: {
        ip: "127.0.0.1",
        port: 80
    }
});

Create public folders

Note: default public folder is ./public (searching as cwd/project dir/public)

config/default.json

{
    "gluon": {
        "publicSource": "./static"
        // or
        "publicSource": [
            "./public", // public has more priority than static one
            "./static"
        ]
    }
}

or

const gluon = require('gluon');
const app = gluon({
    publicSource: './public',
});

Ignore a route

You might want to ignore a route that shouldn't routed by gluon itself. Maybe you want to use this for other purposes.

routes/authentication.js

const gluon = require('gluon');
const router = gluon.router(null, true);

router.use((req, res, next) => {
    if(authentication check..) return res.unauthorized('you must log in'); 
    next();
});

module.exports = router;

routes/logout.js

const gluon = require('gluon');
const router = gluon.router();

router.use(require('./authentication'));
router.all('/', (req, res) => {
    logout..
});

module.exports = router;

Authentication and role management

With gluon 1.3.0 token based authentication generator released. Generator uses sequelize to communicate database. Creates 2 tables, "Role" and "Token". Before doing anything, make database connection correctly. Lets look properties

config/default.json

{
    "gluon": {
        "auth": {
            "base": "token"
        }
    }
}

gluon/auth only works if you set base = "token"

config/default.json

{
    "gluon": {
        "auth": {
            "base": "token",
            "model": "user", // which model is owner of token. Make sure your model is exist in your models folder.
            "disable": false, // default= false, if you just disable authentication for some purpose, set this to true
            "expire": 43200, // default=43200, how much seconds will be need for token to expire?
            "allow": [
                "/authentication/does/not/exist/in/this/path",
                "/login", // default you can't block /login
                "/register", // same here these are default.
                "/dashboard",
                "/blabla/:id", // you can do this too. but only format is ":xxxx" nothing more, simply makes "[^\/]*" regex
                "regexp:^/damn/you/know+/regexp" // you can use regexp with this "regexp:" prefix
            ],
            "routes": {
                "/admin": "admin", // simply /admin for only "admin" role owners
                "/see": "canSee",
                "/see/important": "important", // this route will require both "canSee" and "important" roles
                "/edit/:id": "canEdit"
            },
            "token": "./token", // If you don't know what are you doing, Don't change this. This setting simply changes the token model
            "role": "./role" // Same as here if you don't know bla bla.. Don't change it..
        }
    }
}

Thats enough for configurations. Simply routes make static blocks. If you want to dynamic blocks you must use req.auth

  • req.auth.login(model): creates token for model
  • req.auth.logout(): removes token
  • req.auth.hasRole(role): checks for role
  • req.auth.addRole(role): adds role
  • req.auth.removeRole(role): removes role
  • req.auth.hasRoles(roles): checks for roles
  • req.auth.addRoles(roles): adds roles
  • req.auth.removeRoles(roles): removes roles

routes/login.js

const gluon = require('gluon');
const router = gluon.router();
const User = require('../models/user');

router.get('/', (req, res) => {
    // controls etc..
    // fetch model that defined in "gluon.auth.model"
    User.find({
        where: {}
    }).then((user) => {
        req.auth.login(user).then((token) => {
            res.ok(token.code);
        });
    });
});

module.exports = router;

routes/someServiceThatHasAuthentication.js

// note this route isn't allowed directly. Directly allowing means closing authentication for that route.
const gluon = require('gluon');
const router = gluon.router();

router.get('/:id', (req, res) => {
    // lets say i need to check some dynamic role "canEditDoor5"
    req.auth.hasRole("canEditDoor" + req.params.id).then((has) => {
        // if user has canEditDoor5 then has will be true
    });

    // you can add these roles by using some database tools or direct `req.auth.addRole`
    req.auth.addRole("canEditDoor" + req.params.id).then((role) => {

    });

    // if you want to change some user's role then
    const Role = require('gluon/role'); // gather role model
    Role.addRole(id of user, "canEditDoor5").then((role) => {

    });
});

module.exports = router;

By time tokens will stay there. You must use node-schedule or similar cron job tools. You can use this.

app.js

const gluon = require('gluon');
const schedule = require('node-schedule');
const app = gluon({
  ready: () => {
    const Token = require('gluon/token');
    schedule.scheduleJob('*/10 * * * *', () => { // remove expired tokens for every 10 minutes
      Token.destroy({
        where: {
          expire: {
            $lt: new Date
          }
        }
      });
    });
  }
});

Parameter routes

If you want to use parameter but you don't want to create single file. You can use @name syntax for folders. for ex:

/routes/index.js -> /
/routes/@id/index.js -> /:id
/routes/dashboard/@dashboard_id/index.js -> /dasboard/:dashboard_id
/routes/fridge/@id/index.js -> /fridge/:id
/routes/fridge/@id/dashboard.js -> /fridge/:id/dashboard
/routes/fridge/@id/temperature/@temperature_id.js -> /fridge/:id/temperature/:temperature_id

Logger special variables

app.js

var logger = require('gluon/logger');
var cluster = require('cluster');
logger.set('worker_id', cluster.worker ? cluster.worker.id : '-');

config

{
  "logger": {
    "level": "LOG",
    "type": "clusterLogger",
    "clusterLogger": "WORKER {var.worker_id} {date} {time} {type} {file}:{line} {message}"
  }
}
1.8.4

7 years ago

1.8.3

7 years ago

1.8.2

7 years ago

1.8.1

7 years ago

1.8.0

7 years ago

1.7.5

7 years ago

1.7.4

7 years ago

1.7.3

7 years ago

1.7.2

7 years ago

1.7.1

7 years ago

1.7.0

7 years ago

1.6.0

7 years ago

1.5.2

8 years ago

1.5.1

8 years ago

1.5.0

8 years ago

1.4.4

8 years ago

1.4.3

8 years ago

1.4.2

8 years ago

1.4.1

8 years ago

1.4.0

8 years ago

1.3.1

8 years ago

1.3.0

8 years ago

1.2.9

8 years ago

1.2.8

8 years ago

1.2.7

8 years ago

1.2.6

8 years ago

1.2.5

8 years ago

1.2.4

8 years ago

1.2.3

8 years ago

1.2.2

8 years ago

1.2.1

8 years ago

1.2.0

8 years ago

1.1.1

8 years ago

1.1.0

8 years ago

1.0.0

8 years ago