UNPKG

qwebs

Version:
360 lines (283 loc) 9.72 kB
# Qwebs Web application framework with native promise, dependency-injection and bundle. [![NPM][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![NPM Download][npm-image-download]][npm-url] [![Dependencies Status][david-dm-image]][david-dm-url] Discover our [starter kit](https://www.npmjs.com/package/qwebs-starter-kit-polymer) with [Polymer](https://www.polymer-project.org/). # Features * [Promise](#promise) * [Separate routes and services](#service) * [Dependency injection](#di) * [Object oriented programming (OOP)](#oop) * [Compression & minification](#bundle) * [0 disk access at runtime](#disk) * [Bundle](#bundle) css, [sass](https://www.npmjs.com/package/node-sass) * [Configuration](#config) # Installation ```shell npm install $qwebs --save npm install $qwebs-http --save ``` ## Create a service.js ```service.js "use strict"; class Service { constructor() { }; index(request, response) { let content = { text: `hello ${request.params.name}` }; return response.send({ request: request, content: content }); }; exports = module.exports = Service; ``` ## Define routes.json ```routes.json { "services": [ { "name": "$http", "location": "qwebs-http"}, { "name": "$service", "location": "./service"} ], "locators": [ { "get": "/:name", "service": "$service", "method": "index" }, ] } ``` ## Create config.json ```config.json { "routes": "./routes.json", "http": { "port": 3000 } } ``` ## Enjoy Create a server.js ```server.js "use strict"; const Qwebs = require("qwebs"); new Qwebs().load(); ``` Run server on http://localhost:3000 ```shell node server.js ``` # Routing Our goal is to find the final route as fast as possible. We use a tree data structure to represent all routes. * get(route, service, method) * post(route, service, method) * put(route, service, method) * patch(route, service, method) * delete(route, service, method) ```routes.json { "services": [ { "name": "$user", "location": "../services/info"} ], "locators": [ { "get": "/user/:id", "service": "$user", "method": "get" }, { "post": "/user", "service": "$user", "method": "save" } ] } ``` ```or in javascript qwebs.get("/user/:id", "$users", "get"); qwebs.post("/user", "$users", "save"); ... ``` # Services <a name="service"/> Qwebs is deigned for POO. Create service, define a route and attached them in routes.json. Qwebs has an dependency injector for easier integration. ```service.js class ApplicationService { //$config service is automatically injected constructor($config) { if ($config.verbose) console.log("ApplicationService created."); }; //send javascript object get(request, response) { let content = { message: "Hello World" }; return response.send({ request: request, content: content }); }; //send stream stream(request, response, reject) { let stream = fs.createReadStream('file.txt') .on("error", reject) //reject Promise .pipe(new ToUpperCase()) //transform .on("error", reject) //reject Promise return response.send({ request: request, stream: stream }); }; }; exports = module.exports = ApplicationService; ``` <a name="di"/> ## Dependency injection Just declare the service name in your constructor. ```services/user.js class UserService { //Config service wil be created as a singleton and injected when UserService will be created constructor($config) ``` Qwebs will create your service with its dependencies. ```routes.json { "services": [ { "name": "$user", "location": "../services/user"} ... ``` ```on server.js //server.js qwebs.inject("$user", "./services/user"); ``` <a name="response"/> ## Response Http response are automatically extended to compressed with Gzip or Deflate. * response.send({request, statusCode, header, content, stream}) - [request](https://nodejs.org/api/http.html#http_class_http_clientrequest) - [statusCode](http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1) - [header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.2) - content: js, html, json, ... *(call response.write(content))* - or - [stream](https://nodejs.org/api/stream.html) *(call stream.pipe(response))* You could override this default behaviour with POO. Override the default response service and inject the new one in Qwebs. <a name="oop"/> ##### How override response.send ? ```services/my-response.js "use strict"; const DataError = require("qwebs").DataError; const ResponseService = require("qwebs/lib/services/response"); class MyResponseService extends ResponseService { constructor() { super(); }; send(response, dataToSend) { return new Promise((resolve, reject) => { if (dataToSend == undefined) reject(new DataError({ message: "No data." })); dataToSend.header = data.header || {}; dataToSend.header["Cache-Control"] = "private"; dataToSend.header["Expires"] = new Date(Date.now() + 3000).toUTCString(); return super.send(response, dataToSend).then(resolve).catch(reject); }); }; }; exports = module.exports = MyResponseService; ``` Then replace $response service in $injector. ```routes.json { "services": [ { "name": "$response", "location": "../services/my-response"} ] } ``` ```or server.js qwebs.inject("$response", "./services/my-response"); ``` <a name="disk"/> ## Avoid disk access at runtime All assets are loaded in memory at startup. Uploaded images are not saved in temporary files. $qjimp service is designed to read, manipulate image stream. <a name="bundle"/> ## Bundle (bundle.json) You could create your own css or js bundle without WebPack. Qwebs includes a [Sass](https://www.npmjs.com/package/node-sass) preprocessor. You don't need to compile your sass via an external program. ```bundle.json { "/app.js":[ "bower_components/angular-material/angular-material.js", "bower_components/angular-route/angular-route.js", "bower_components/angular-aria/angular-aria.js", "bower_components/angular-sanitize/angular-sanitize.js", "bower_components/angular-i18n/angular-locale_fr-fr.js", "bower_components/angular-animate/angular-animate.js", "web/app.js" ], "/app.css":[ "assets/mixins.scss", "bower_components/angular-material/angular-material.css", "assets/master.scss" ] } ``` ```html <!DOCTYPE html> <html> <head> <link rel=stylesheet type="text/css" href="/app.css"> </head> <body> <script src="/app.js"></script> </body> </html> ``` # Configuration <a name="config"/> * CORS ```config.json { "cors": { "enabled": true, "allow-origin": "*", "max-age": 3600, "allow-headers": "Content-Type, Access-Control-Allow-Headers, Authorization" } } ``` <a name="promise"/> ## Promise * Easier to read * Easier to maintain in the future * Easier error handling ## Services * $config: your configuration. * $qwebs: qwebs instance. * $injector: resolve services at runtime. * $responseProxy: extand http.ServerResponse. * $response: default response extension. * $qjimp: convert and manipulate images. ## Others Services * [$http](https://www.npmjs.com/package/qwebs-http) * [$https](https://www.npmjs.com/package/qwebs-https) * [$http-to-https](https://www.npmjs.com/package/qwebs-http-to-https) * [$mongo](https://www.npmjs.com/package/qwebs-mongo) * [$authentication](https://www.npmjs.com/package/qwebs-auth-jwt) * [$https](https://www.npmjs.com/package/qwebs-https) * [$nodemailer](https://www.npmjs.com/package/qwebs-nodemailer) * [$bitbucket](https://www.npmjs.com/package/qwebs-bitbucket-deploy) * [$aws-s3](https://www.npmjs.com/package/qwebs-aws-s3) * [$aws-ses](https://www.npmjs.com/package/qwebs-aws-ses) * [aws api gateway](https://www.npmjs.com/package/qwebs-aws-api-gateway) ## Examples To run our examples, clone the Qwebs repo and install the dependencies. ```bash $ git clone https://github.com/BenoitClaveau/qwebs --depth 1 $ cd qwebs $ npm install $ cd exemples/helloworld $ node server.js ``` ## Test To run our tests, clone the Qwebs repo and install the dependencies. ```bash $ git clone https://github.com/BenoitClaveau/qwebs --depth 1 $ cd qwebs $ npm install $ cd tests $ node.exe "..\node_modules\jasmine\bin\jasmine" --verbose . ``` [npm-image]: https://img.shields.io/npm/v/qwebs.svg [npm-image-download]: https://img.shields.io/npm/dm/qwebs.svg [npm-url]: https://npmjs.org/package/qwebs [travis-image]: https://travis-ci.org/BenoitClaveau/qwebs.svg?branch=master [travis-url]: https://travis-ci.org/BenoitClaveau/qwebs [coveralls-image]: https://coveralls.io/repos/BenoitClaveau/qwebs/badge.svg?branch=master&service=github [coveralls-url]: https://coveralls.io/github/BenoitClaveau/qwebs?branch=master [david-dm-image]: https://david-dm.org/BenoitClaveau/qwebs/status.svg [david-dm-url]: https://david-dm.org/BenoitClaveau/qwebs