[컴][nodejs] krakenjs

크라켄 /expressjs framework

Kraken, Krakenjs

kraken 은 express의 middleware 들을 모아놓은 것이라고 보면 된다. 그래서 middleware 작성법을 살짝 보고나면 kraken 을 이해하기가 쉬워질 것이다.

기본적으로 kraken 은 express 새롭게 설정하고, krarken 이 가지고 있는 middleware 들을 더해서 새로운 express 로 대체하게 된다. 즉, express 의 bootstrap 부분이 새롭게 작성된 express 인 것이다.(참고: kraken-js/index.js)

선택이유

krkenjs 는 '보안', 'i18n', 'view' 정도를 제공해 준다. 그리고 어느정도 자유로운 express 의 구조(structure)를 잡아준다. paypal 에서 kraken 을 만든 이유는 아래 링크를 확인해보자.

paypal 에서 kraken 을 만들때 사용한 이유와 더불어, 현재 expressjs 를 기반으로 하는 여러 framework 가 있는데, 결국 오래 지속될 수 있는 녀석을 선택해야 한다. 그런데 어느것이 주류라고 할만한 것이 없었다. 그렇기 때문에 가장 간단하고, 추후에 지원을 해주지 않아도 source 를 분석해서 마음대로 사용할 만한 녀석으로서 kraken 을 선택했다.

  • source code 분석이 용이

issue

현재 node v12 이상에서 krakenjs Getting Started 에서 설명하는 yo kraken 이 제대로 동작하지 않는다. kraken github 의 issue 에도 올라와 있다. 그래서 해결책은 node version 을 변경해서 일단 template 을 만들고 그 template 을 복사해서 사용하면 된다.

view dustjs

하지만 여전히 grunt 를 사용해서 dustjs 를 호출하는 부분이 있는데, view 부분의 compile 은 아래처럼 할 수 있다. 나머지는 view 에 대한 path 부분과, compile 된 결과물 .js 들을 복사해서 한곳에 모아 놓는 것이다.

cd <proj_path>
.\node_modules\.bin\dustc.cmd -s public/templates/**/*.dust

with typescript

route, express-enroute

krarken 은 이 express-enroute middleware 를 이용해서 route 를 해준다. 그래서 config.jsonrouter field 의 값들은 krakenjs/express-enrouten configuration 를 참고하면 된다.

예시는 여기 를 참고하자.

// config/config.json
{
  ...
    "router": {
      "module": {
        "arguments": [{ "directory": "path:./controllers" }]
      }
    }

  }
}

meddleware

kraken 에서 middleware 를 meddleware 라는 module 안으로 가져가서 사용한다. 이 module 도 결국 express의 middleware 로 동작하는데, 내부에서 다른 middleware 를 등록해준다. 이때 middleware:before, middleware:after 등의 event 를 발생시킨다. 그리고 github 에서 확인할 수 있지만 미들웨어 등록순서 설정, priority 등 다른 부수적인 기능들을 해준다.

기본적으로 config.jsonmiddleware 부분에서 설정을 하게 된다. krakenjs 에서 기본적으로 되어 있는 설정은 여기서 확인하면 된다.

custom middleware 사용법

auth with passport

kraken 에서 passport 를 사용한 authentication 예제를 제공한다.

passport 동작

csrf

{
    "middleware": {
        ...
        "appsec": {
            "enabled": true,
            "priority": 110,
            "module": {
                "name": "lusca",
                "arguments": [
                    {
                        // "csrf": true,
                        "xssProtection": true,
                        "xframe": "SAMEORIGIN",
                        "p3p": false,
                        "csp": false
                    }
                ]
            }
        },
        ...
    }
    
}

session with redis

기본적으로 krakenjs 에서 express-session 을 사용하지만 conect-redis 에서 사용해야 해서 express-session package 를 추가한 후 connect-redis 의 설정을 해주고, 우리쪽에서 express-session 을 던져주는 방식으로 connect-redis 를 사용하면 된다.(참고: https://github.com/i5on9i/krakenjs-example/commit/9258add5f6e10cc552d5f6da716f57e90475ce90)

npm install --save redis connect-redis express-session

// config/config.json 
{ \"middleware\": {

    "session": {
        "module": {
            "name": "path:./lib/middleware/redis-session",
            "method": "conRedis",
            "arguments": [
                {
                    "key": "",
                    "secret": "80bc6d67f80813ccc78ff77adf0eefcafa7eeef6",
                    "cookie": {
                        "path": "/",
                        "httpOnly": true,
                        "maxAge": null
                    },
                    "proxy": null
                },
                {
                    "host": "192.168.0.26",
                    "port": 6379
                }
            ]
        }
    },

    "router": {
      "module": {
        "arguments": [{ "directory": "path:./controllers" }]
      }
    }

} }

// ./lib/middleware/redis-session.ts
import redis from 'redis';
import session from 'express-session';
import credis from 'connect-redis';

const RedisStore = credis(session);

export function conRedis(settings: any, redisConfig: any) {
    const redisClient = redis.createClient(redisConfig)
    settings.store = new RedisStore({ client: redisClient });

    return session(settings);
};

NODE_ENV

kraken 은 NODE_ENV 값을 보고 config/*.json 의 파일을 선택한다. 그래서 환경변수를 set 해주자. package.json에 set 을 하려면 여기를 참고하자.

  • undefined or dev[elopment] : development.json
  • test[ing] : test.json
  • stag[e|ing]: staging.json
  • prod[uction]: config.json

ORM 사용

async/await in Expressjs

from kraken-js

"kraken-js": {
  "version": "2.3.0",
  "resolved": "https://registry.npmjs.org/kraken-js/-/kraken-js-2.3.0.tgz",
  "integrity": "sha512-etX75OAtXSyMDQernDHMc9iQ0HzilVI/MWdtztikU2s4qpTbvhQqlBLzK+EHdi6wl9+5NGfTSTwfUIaM2vrt0w==",
  "requires": {
      "bluebird": "^3.4.7",
      "body-parser": "^1.12.2",
      "caller": "^1.0.0",
      "compression": "^1.4.3",
      "confit": "^2.0.3",
      "cookie-parser": "^1.3.4",
      "core-util-is": "^1.0.1",
      "debuglog": "^1.0.1",
      "depd": "^1.0.1",
      "endgame": "^1.0.0",
      "express-enrouten": "^1.2.0",
      "express-session": "^1.10.4",
      "formidable": "^1.0.17",
      "lusca": "^1.5.1",
      "meddleware": "^3.0.2",
      "morgan": "^1.5.2",
      "serve-favicon": "^2.2.0",
      "serve-static": "^1.9.2",
      "shortstop": "^1.0.1",
      "shortstop-handlers": "^1.0.0",
      "shortstop-resolve": "^1.0.1",
      "shush": "^1.0.0"
  }
},

kraken bootstrap

app = module.exports = express();
app.use(kraken(options));

// express/lib/application.js
app.use = function use(fn) {
  ...

  // setup router
  this.lazyrouter();
  var router = this._router;

  fns.forEach(function (fn) {

    ...

    // restore .app property on req and res
    router.use(path, function mounted_app(req, res, next) {
      var orig = req.app;
      fn.handle(req, res, function (err) {
        setPrototypeOf(req, orig.request)
        setPrototypeOf(res, orig.response)
        next(err);
      });
    });

    // mounted an app
    fn.emit('mount', this);
  }, this);

  return this;
};

// kraken-js/index.js
module.exports = function (options) {
    ...

    app = express();
    app.once('mount', function onmount(parent) {
      ...
      promise = bootstrap(parent, options);
      ...
    })
    return app;
}

// kraken-js/lib/bootstrap.js
module.exports = function (app, options) {

    endgame(options.uncaughtException);

    return settings(app, options)
        .then(views)
        .then(middleware)
        .then(events)
        .then(function complete() {
            debug('init complete');
        });
};

댓글 없음:

댓글 쓰기