gluon
v1.8.4
Published
Manager of project database, models, routes, logging, authentication, roles and many more..
Downloads
74
Maintainers
Readme
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
andconfig
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 serializepassword
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 ascwd/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 modelreq.auth.logout()
: removes tokenreq.auth.hasRole(role)
: checks for rolereq.auth.addRole(role)
: adds rolereq.auth.removeRole(role)
: removes rolereq.auth.hasRoles(roles)
: checks for rolesreq.auth.addRoles(roles)
: adds rolesreq.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}"
}
}