Teo.js
Please, meet yet another Node.js based web-framework.
Installing the framework
NPM
npm install teo.js -g
Clone git repo
git clone https://github.com/Antyfive/teo.js.git
Setup
Create test project
mkdir myproject
cd myproject/
npm install teo.js
(or alternatevly, npm install teo.js -g
to setup package globally )teo setup dev
(will setup, and generate new project)
If teo
executable is not working, update your PATH variable:
export PATH="$PATH:./node_modules/.bin"
Config
So, how to create config, which will be applied to your app?
In home directory of your application, just create config
directory, and place inside your *.js
file.
Here is default set of currently available properties:
protocol: "http",
host: "localhost",
port: 3000,
delimiters: '{{ }}',
cache: {
"static": false,
"response": false
},
appDirs: ["models", "controllers"],
appFiles: ["app.js"],
cookie: {
keys: ["signed key"]
},
session: {
sessionKeyName: "SID",
secret: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
lifetime: {
session: 60 * 60 * 24 * 10
},
storageType: "memory"
},
csrf: {
keyName: "_csrfToken",
secret: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
},
cluster: {
enabled: true
},
db: {
enabled: false,
ormName: "waterline",
adapterName: "teo.db.adapter.waterline",
adapterConfig: {
adapters: {
"default": "sails-disk",
disk: "sails-disk",
mysql: "sails-mysql"
},
connections: {
myLocalDisk: {
adapter: "disk"
},
myLocalMySql: {
adapter: "mysql",
host: "localhost",
database: "foobar"
}
}
}
}
Also, config is allowed to be splitted into development & production modes. Here is example of config for the test application:
module.exports = {
"production": {
protocol: "http",
host: "localhost",
port: 3000,
cache: {
"static": true,
"response": true
}
},
"development": {
protocol: "http",
host: "localhost",
port: 3100,
cache: {
"static": false,
"response": false
}
},
delimiters: '{{ }}'
};
Project structure
apps/-|
| your_app_dir/--|
| config/
| controllers/
| models/
| public/
| views/
| app.js // adittional app.js for your extra logic
node_modules/
app.js
App structure explained
Config
Place your *.js configs inside. Example of config you can see above.
Controllers
Directory is used for controllers.
Lets take a look what we can do inside the controller:
module.exports = function(client, db) {
console.log( "Index controller was initialized!" );
client.get("/my/url/:id", function(req, res) {
res.render("index", {
partial: {
id: "myid"
},
title: "Title"
}, function() {});
});
client.get("/json/:id", function(req, res, next) {
res.json({ id: req.params.id, 'title': "title" });
});
client.get("/:id/:title", function(req, res, next) {
next({ id: req.params.id, "title": req.params.title });
});
client.get("/get/news.json", function(req, res) {
res.send({ id: 1, title: "title" });
});
client.get("/get/error/404", function(req, res) {
res.send(404);
});
};
Basically, urls parsing is implemented in well-known express
style.
res
Let's go through current res
mixins.
res.render
(templateName, contextObj, [callback])
res.render("index", {
partial: {
id: "test"
},
title: "Title"
}, function(err, output) {
});
With that said, if callback wasn't passed, framework will do res.end
with compiled output (layout with partial).
res.json
(obj)
Ends response with json, in your own format of response. Otherwise, framework will provide standartized format of json response. We will discuss it in next chapters.
res.json({test: "test"});
res.send
(repsonse) || (errCode, message)
This method commonly used to end your response. If you want to send JSON, you don't need to use JSON.stringify
. Just pass object:
res.send({myVal: "1"});
Content-Type will be matched automatically inside.
How Content-Type is set inside res.send
method?
It can be detected in next ways:
- Based on
Accept
header from request. - Based on extension from the url. I.e.
/my/action.json
extension will be parsed as json
, and then MIME
type will be matched. - If object is passed, in this case
application/json
will be set. - Otherwise, if
MIME
type is not found, text/html
will be set.
Default response format using res.send
{
code: code,
data: {
myVal: "1"
},
message: "string"
}
Sending an error with res.send
res.send(500, "My error message");
Alternately, you can just send your response code. And response text will be matched in http.STATUS_CODES
.
res.send(500);
req
Now, let's take a look on req
mixins.
req.cookie
Cookies are flavoured with https://github.com/pillarjs/cookies
Feel free to use it's api via req.cookie
.
req.session
Currently session have simple api, which consists of two methods:
req.session.set
(key, val)
Setter of value to the storage.
req.session.set("myKey", "myVal");
req.session.get
(key)
Getter of value by key.
var val = req.session.get("myKey");
req.csrf
Basically CSRF is handled out of the box, and everything will be set, and handlerd on the level of framework. But, API is available as well.
req.csrf.genToken
()
Generates token.
req.csrf.getToken
()
Getter of token.
req.csrf.setToken
(key)
Setter of token.
req.csrf.generateHash
()
Generates new hash.
req.params
Object of parsed url params
client.get('/get/:id', function(req, res) {
cosole.log("My id:" + req.params.id);
});
req.query
Object of parsed GET parameters
http://localhost:3100/?myParam=1&myParam2=2
Will parse it to req.query
object:
{
"myParam": "1",
"myParam2": "2"
}
Database
Config example:
db: {
enabled: true,
ormName: "waterline",
adapterName: "teo.db.adapter.waterline",
adapterConfig: {
adapters: {
"default": "sails-disk",
disk: "sails-disk",
mysql: "sails-mysql"
},
connections: {
myLocalDisk: {
adapter: "disk"
},
myLocalMySql: {
adapter: "mysql",
host: "localhost",
database: "foobar"
}
}
}
}
Scheme how ORM works:
DB client -> ORM wrapper for particular external ORM -> Teo.js ORM Adapter
All DB-related work is done by framework in background. Models will be loaded, and DB will be connected on Application start.
The only thing you need, is to manually install external ORM, and adapters.
Db client is available in every controller, and in your app.js (Considering, you have ./apps/your_app/app.js
file).
Example of controller with usage of db
module.exports = {
identity: 'users',
connection: 'myLocalDisk',
attributes: {
first_name: 'string',
last_name: 'string'
}
};
module.exports = function(client, db) {
client.get("/users", function(req, res) {
db.collection("users").find().exec(function(err, models) {
if (err) {
return res.send(500, err.message);
}
res.send(models.toJSON());
});
});
}
As for now, the fist ORM wrapper, and adapter is implemented for Waterline.
Main API methods of DB client
db.collection
(stringName)
Getter of collection by it's name.
db.collections
()
Getter of all loaded collections hash.
db.connect
(callbackFn)
Connect to DB.
db.disconnect
(callbackFn)
Disconnect from DB.
Middleware
Middleware is implemented in express
style.
Considering, you have ./apps/your_app/app.js
file:
module.exports = function(client) {
this.middleware(function(req, res, next) {
});
}
Attention! Default status code is set to 500.
Logger
success(msg)
info(msg)
warn(msg)
error(msg)
fatal(msg)
log(msg)
Each log message type has it's own output color.
logger.log("Message")
outputs in format:
[Thu Mar 19 2015 10:11:12 GMT] Success: Message
Extensions
Framework supports external extensions.
Extensions can be loaded into the system as externally installed npm modules, or as local files (your own local extensions).
Extensions config
extensions: {
filePath: "/extensions",
extensionsList: [
{
"name": "powered-by",
"module": "teo-powered-by-extension"
},
{
"name": "html-compressor",
"file": "myCompressor"
}
]
}
Extension example
module.exports = {
extension: function(app) {
app.middleware(function(req, res, next) {
res.setHeader("X-Powered-By", "Teo.js v" + version);
next();
});
}
};
To be continued...