Yet Another Event Promised Server

Written by evheniybystrov | Published 2017/08/25
Tech Story Tags: javascript | nodejs | express | koa | yeps

TLDRvia the TL;DR App

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 nodeconst 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 middlewareconst 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.


Published by HackerNoon on 2017/08/25