Web application framework with native promise, dependency-injection and bundle.
Discover our starter kit with Polymer.
- Promise
- Separate routes and services
- Dependency injection
- Object oriented programming (OOP)
- Compression & minification
- 0 disk access at runtime
- Bundle css, sass
- Configuration
npm install $qwebs --save
npm install $qwebs-http --save
"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;
{
"services": [
{ "name": "$http", "location": "qwebs-http"},
{ "name": "$service", "location": "./service"}
],
"locators": [
{ "get": "/:name", "service": "$service", "method": "index" },
]
}
{
"routes": "./routes.json",
"http": {
"port": 3000
}
}
Create a server.js
"use strict";
const Qwebs = require("qwebs");
new Qwebs().load();
Run server on http://localhost:3000
node server.js
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");
...
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.js
qwebs.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"
]
}
<!DOCTYPE html>
<html>
<head>
<link rel=stylesheet type="text/css" href="/app.css">
</head>
<body>
<script src="/app.js"></script>
</body>
</html>
- 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
- $config: your configuration.
- $qwebs: qwebs instance.
- $injector: resolve services at runtime.
- $responseProxy: extand http.ServerResponse.
- $response: default response extension.
- $qjimp: convert and manipulate images.
- $http
- $https
- $http-to-https
- $mongo
- $authentication
- $https
- $nodemailer
- $bitbucket
- $aws-s3
- $aws-ses
- aws api gateway
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
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 .