Qwebs
Web application framework with native promise, dependency-injection and bundle.
Discover our starter kit with Polymer.
Features
- Promise
- Separate routes and services
- Dependency injection
- Object oriented programming (OOP)
- Compression & minification
- 0 disk access at runtime
- Bundle css, sass
- Configuration
Installation
npm install $qwebs --savenpm install $qwebs-http --save
Create a 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
{ "services": [ { "name": "$http", "location": "qwebs-http"}, { "name": "$service", "location": "./service"} ], "locators": [ { "get": "/:name", "service": "$service", "method": "index" }, ]}
Create config.json
{ "routes": "./routes.json", "http": { "port": 3000 }}
Enjoy
Create a server.js
"use strict"; const Qwebs = require("qwebs");new Qwebs().load();
Run server on http://localhost:3000
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)
{ "services": [ { "name": "$user", "location": "../services/info"} ], "locators": [ { "get": "/user/:id", "service": "$user", "method": "get" }, { "post": "/user", "service": "$user", "method": "save" } ]}
qwebs.get("/user/:id", "$users", "get"); qwebs.post("/user", "$users", "save");...
Services
Qwebs is deigned for POO. Create service, define a route and attached them in routes.json. Qwebs has an dependency injector for easier integration.
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;
Just declare the service name in your constructor.
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.
{ "services": [ { "name": "$user", "location": "../services/user"} ...
//server.jsqwebs.inject("$user", "./services/user");
Http response are automatically extended to compressed with Gzip or Deflate.
- response.send({request, statusCode, header, content, stream})
- request
- statusCode
- header
- content: js, html, json, ... (call response.write(content))
- or
- stream (call stream.pipe(response))
You could override this default behaviour with POO. Override the default response service and inject the new one in Qwebs.
##### 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"}
]
}
qwebs.inject("$response", "./services/my-response");
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.
## Bundle (bundle.json)You could create your own css or js bundle without WebPack. Qwebs includes a Sass preprocessor. You don't need to compile your sass via an external program.
{ "/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" ] }
Configuration
- CORS
{ "cors": { "enabled": true, "allow-origin": "*", "max-age": 3600, "allow-headers": "Content-Type, Access-Control-Allow-Headers, Authorization" }}
- 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
- $http-to-https
- $mongo
- $authentication
- $https
- $nodemailer
- $bitbucket
- $aws-s3
- $aws-ses
- aws api gateway
Examples
To run our examples, clone the Qwebs repo and install the dependencies.
$ 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.
$ git clone https://github.com/BenoitClaveau/qwebs --depth 1$ cd qwebs$ npm install$ cd tests$ node.exe "..\node_modules\jasmine\bin\jasmine" --verbose .