Yet Another Event Promised Server
Many of us use node.js with express in our job or own projects. But now we can use such interesting features like async/await. We can use koa or make error handler wrapper for express. But it’s not cool.
Express and koa use middleware in kernel as the main pattern. It’s copied from Ruby framework sinatra and it’s not asynchronous. You can compare it with loop — not declarative and non asynchronous.
If you look how node.js server works you can see single process with “request” events.
const http = require('http');
const server = http.createServer( (req, res) => {
ctx.res.statusCode = 200;
res.end('okay');
});
And with promises:
const http = require('http');
const server = http.createServer( (req, res) => {
Promise.resolve({ req, res })
.then(ctx => {
ctx.res.statusCode = 200;
ctx.res.end('okay');
return ctx;
});
});
So if you use loop or middleware or any non asynchronous code all other request will be waiting. The main idea of node.js and javascript is to use non blocking actions. That’s why we have callbacks, promises and async/await.
So after researching I decided to create a new framework. Let’s meet YEPS.
npm i -S yeps
app.js
const App = require('yeps');
const app = module.exports = new App();
app.then(async ctx => {
ctx.res.statusCode = 200;
ctx.res.end('Ok');
});
app.catch(async (err, ctx) => {
ctx.res.statusCode = 500;
ctx.res.end(err.message);
});
bin/www
#!/usr/bin/env node
const http = require('http');
const app = require('../app');
http
.createServer(app.resolve())
.listen(parseInt(process.env.PORT || '3000', 10));
package.json
"scripts": {
"start": "node bin/www"
}
First of all it’s 100% promise based framework — no blocking actions in kernel.
Promise like middleware
app.then(async ctx => {
ctx.res.end('test');
return app.reject(); // the same as Promise.reject()
}).then(async () => {
// it wont work
}).catch(async () => {
// it wont work
});
You can check it by yourself just look benchmark results. I tested YEPS with koa and express.
YEPS gives possibility to execute modules in parallel mode using Promise.all().
const App = require('yeps');
const app = new App();
const error = require('yeps-error');
const logger = require('yeps-logger');
app.all([
logger(),
error()
]);
app.then(async ctx => {
ctx.res.writeHead(200, {'Content-Type': 'text/plain'});
ctx.res.end('Ok');
});
app.catch(async (err, ctx) => {
ctx.res.writeHead(500);
ctx.res.end(err.message);
});
Or
app.all([
logger(),
error()
]).then(async ctx => {
ctx.res.writeHead(200, {'Content-Type': 'text/plain'});
ctx.res.end('Ok');
}).catch(async (err, ctx) => {
ctx.res.writeHead(500);
ctx.res.end(err.message);
});
It’s useful if you need to make connection to DB and make some other stuff like registration logging system, error handler…
The same idea we can use for routing. You don’t need to think which router is the most popular and put it higher like for express. We can start checking all routers at the same time and reject checking if we found it.
const Router = require('yeps-router');
const router = new Router();
router.catch({ method: 'GET', url: '/' }).then(async ctx => {
ctx.res.writeHead(200);
ctx.res.end('homepage');
});
router.get('/test').then(async ctx => {
ctx.res.writeHead(200);
ctx.res.end('test');
}).post('/test/:id').then(async ctx => {
ctx.res.writeHead(200);
ctx.res.end(ctx.request.params.id);
});
app.then(router.resolve());
And last but not least if you already have some express middlewares you can use express wrapper and it’s easy to migrate just look into YEPS modules.
And some more examples:
const App = require('yeps');
const server = require('yeps-server');
const app = new App();
const error = require('yeps-error');
const Router = require('yeps-router');
const router = new Router();
const wrapper = require('yeps-express-wrapper');
const path = require('path');// express middleware
const bodyParser = require('body-parser');
const favicon = require('serve-favicon');
app.then(wrapper(favicon(path.join(__dirname, 'public', 'favicon.ico'))));app.all([
error(),
wrapper(bodyParser.json()),
]);
router.get('/').then(async ctx => {
console.log(ctx.req.body);
ctx.res.writeHead(200);
ctx.res.end('test');
});
app.then(router.resolve());
server.createHttpServer(app);
Let’s get fun with node.js.