Marcin Szczepanski (@MarcinS)
Correct!
Requires Node.js v0.11
node --harmony
Suspendable functions / Continuations
function*yield
var generatorFunc = function* () {
yield "Hello";
return "World";
}
var generatorObj = generatorFunc();
generatorObj.next(); // {value: "Hello", done: false}
generatorObj.next(); // {value: "World", done: true}
generatorObj.next(); // Error: Generator has already finished
var generatorFunc = function* () {
var i = 0;
while (true) {
yield i;
i++;
}
}
var generatorObj = generatorFunc();
generatorObj.next(); // {value: 0, done: false}
generatorObj.next(); // {value: 1, done: true}
generatorObj.next(); // {value: 2, done: true}
generatorObj.next(); // {value: 3, done: true}
generatorObj.next(); // {value: 4, done: true}
generatorObj.next(); // {value: 5, done: true}
generatorObj.next(); // ...
var generatorFunc = function* () {
var nextUp = yield "Hello!";
yield nextUp.toLowerCase();
return "World!";
}
var generatorObj = generatorFunc();
generatorObj.next(); // {value: 'Hello!', done: false}
generatorObj.next('OK'); // {value: 'ok', done: false}
generatorObj.next(); // {value: 'World!', done: true}
function doStuff(callback) {
var a,b;
// $.get returns a promise
$.get('http://servicea.com/').then(function (result) {
a = result;
return $.get('http://serviceb.com/?q=' + a);
}).then(function (result) {
b = result;
// callback is node style function(err, ret)
callback(null, [a,b]);
}).catch(function (err) {
callback(err);
});
}
var co = require('co');
co(function* () {
var a = yield $.get('http://servicea.com');
var b = yield $.get('http://serviceb.com?q=' + a);
return [a,b];
})(callback);
coeg. fs.readFile:
function read(path, encoding) {
return function(cb){
fs.readFile(path, encoding, cb);
}
}
co(function* () {
var fileContent = yield read(path, encoding);
})();
app.use(function* (next) {
// ...
yield next;
// ...
});
var koa = require('koa'),
app = koa();
app.use(function* (next) {
this.response.body = "Hello World!";
yield next;
});
app.listen(3000);
app.use(function* _timingMiddleware(next) {
var requestStartTime = +new Date();
yield next;
var requestDuration = (+new Date()) - requestStartTime;
console.log(this.request.method, this.request.path,
"(" + requestDuration + "ms)");
});
var delay = function (timeout) {
return function (cb) {
setTimeout(cb, timeout);
};
};
app.use(function* _delayMiddleware(next) {
yield delay(1000);
yield next;
});
app.use(function* _mainMiddlware(next) {
this.response.body ="Hello world!
";
yield next;
});
this in middlwarerequest and response objectsapp reference and cookies helperthrow function: this.throw(500, 'Something failed!');ctx.headerctx.methodctx.method=ctx.urlctx.url=ctx.pathctx.path=ctx.queryctx.query=ctx.querystringctx.querystring=ctx.typectx.hostctx.host=ctx.freshctx.stalectx.socketctx.protocolctx.securectx.ipctx.ipsctx.subdomainsctx.is()ctx.accepts()ctx.acceptsEncodings()ctx.acceptsCharsets()ctx.acceptsLanguages()ctx.get()ctx.bodyctx.body=ctx.statusctx.status=ctx.lengthctx.length=ctx.typectx.type=ctx.charsetctx.charset=ctx.headerSentctx.redirect()ctx.attachment()ctx.set()ctx.remove()ctx.lastModified=ctx.etag=this.requesthost / method / url / path / queryis() - parse Content-Type:
if (this.is('application/json')) { ... }
accepts() - parse Accepts:
switch (this.accepts('json', 'html', 'text')) {
case 'json': break;
case 'html': break;
case 'text': break;
default: this.throw(406,
'json, html, or text only');
}
acceptsEncodings(), acceptsLanguages(), acceptsCharsets()this.responsebody - String, Buffer, Stream or Objecttype - Content-Typeget() set() for headersredirect()status - set to code or string2.3.2 418 I'm a teapot
Any attempt to brew coffee with a teapot should result in the error code "418 I'm a teapot". The resulting entity body MAY be short and stout.
var koa = require('koa'),
app = koa();
app.use(function* (next) {
if (this.path === '/') {
this.body = "Home Page
";
} else if (this.path === '/info') {
switch(this.accepts('html', 'json')) {
case 'html':
this.body = "Marcin
";
break;
case 'json':
this.body = { name: 'Marcin'};
break;
}
}
yield next;
});
app.listen(3000);
$ curl -i http://localhost:3000/info
HTTP/1.1 200 OK
X-Powered-By: koa
Content-Type: text/html; charset=utf-8
Content-Length: 15
Date: Sun, 09 Mar 2014 20:32:34 GMT
Connection: keep-alive
Marcin
$ curl -i -H"Accept: application/json" http://localhost:3000/info
HTTP/1.1 200 OK
X-Powered-By: koa
Content-Type: application/json
Content-Length: 23
Date: Sun, 09 Mar 2014 20:27:45 GMT
Connection: keep-alive
{
"name": "Marcin "
}
What you'll want to build a web application
koa-static
var serve = require('koa-static');
app.use(serve('./public'));
koa-route
var route = require('koa-route'),
myController = require('./myController');
app.use(route.get('/foo', myController.foo));
app.use(route.post('/foo/new', myController.newFoo));
koa-router
var router = require('koa-router'),
myController = require('./myController');
app.use(router(app));
app.get('/foo', myController.foo);
app.post('/foo/new', myController.newFoo);
var Router = require('koa-router'),
mount = require('koa-mount'),
myController = require('./myController');
var router = new Router();
router.get('/', myController.foo);
router.post('/new', myController.newFoo);
app.use(mount('/foo', router.middleware());
koa-views
var views = require('koa-views');
// views(basePath, engine)
app.use(views('./views', 'jade'));
app.use(function* (next) {
// renders views/index.jade
yield this.render('index', {name: 'Marcin'});
});
There's a fair few of these...
koa-session
var session = require('koa-session');
app.use(session());
app.use(function* () {
var views = this.session.views || 0;
this.session.views = ++views;
this.body = "Number of views: " + views;
});
Again, there's a few of these...
koa-logger
var logger = require('koa-logger');
app.use(logger());
mongodb-logger, koa-log4js, ...
var koa = require('koa'),
logger = require('koa-logger'),
serve = require('koa-static'),
router = require('koa-router'),
views = require('koa-views'),
app = koa();
app.use(logger());
app.use(serve('./public'));
app.use(views('./views', 'jade'));
app.use(router(app));
['infoController', 'homeController'].forEach(function (controller) {
var controllerModule = require('./controllers/' + controller);
controllerModule.register(app);
});
infoController
var info = function* (next) {
var person = {
name: 'Marcin'
};
switch(this.accepts('html', 'json')) {
case 'html':
yield this.render('info', person);
break;
case 'json':
this.body = person;
break;
}
yield next;
};
module.exports.register = function (app) {
app.get('/info', info);
};
koa-passport?koa-body: body parsing (form post, etc)koa-cors, koa-csrfkoa-common: basic standard set of middlwwareMe: @MarcinS