{"id":22688881,"url":"https://github.com/benoitclaveau/qwebs","last_synced_at":"2025-08-07T02:31:15.699Z","repository":{"id":65371938,"uuid":"41811398","full_name":"BenoitClaveau/qwebs","owner":"BenoitClaveau","description":"Promise web server","archived":false,"fork":false,"pushed_at":"2018-03-11T11:25:46.000Z","size":3709,"stargazers_count":3,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-09T19:42:37.373Z","etag":null,"topics":["application","dependency-injection","fast","framework","promise","stream","web"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BenoitClaveau.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-09-02T16:04:24.000Z","updated_at":"2018-11-02T06:39:00.000Z","dependencies_parsed_at":"2023-01-20T01:32:14.742Z","dependency_job_id":null,"html_url":"https://github.com/BenoitClaveau/qwebs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BenoitClaveau%2Fqwebs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BenoitClaveau%2Fqwebs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BenoitClaveau%2Fqwebs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BenoitClaveau%2Fqwebs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BenoitClaveau","download_url":"https://codeload.github.com/BenoitClaveau/qwebs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228982227,"owners_count":18001488,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["application","dependency-injection","fast","framework","promise","stream","web"],"created_at":"2024-12-10T00:16:24.065Z","updated_at":"2024-12-10T00:16:24.665Z","avatar_url":"https://github.com/BenoitClaveau.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Qwebs\n Web application framework with native promise, dependency-injection and bundle.\n\n [![NPM][npm-image]][npm-url]\n [![Build Status][travis-image]][travis-url]\n [![Coverage Status][coveralls-image]][coveralls-url]\n [![NPM Download][npm-image-download]][npm-url]\n [![Dependencies Status][david-dm-image]][david-dm-url]\n\n Discover our [starter kit](https://www.npmjs.com/package/qwebs-starter-kit-polymer) with [Polymer](https://www.polymer-project.org/).\n\n# Features\n\n  * [Promise](#promise) \n  * [Separate routes and services](#service) \n  * [Dependency injection](#di) \n  * [Object oriented programming (OOP)](#oop) \n  * [Compression \u0026 minification](#bundle) \n  * [0 disk access at runtime](#disk) \n  * [Bundle](#bundle) css, [sass](https://www.npmjs.com/package/node-sass)\n  * [Configuration](#config)\n  \n\n\n# Installation\n\n```shell\nnpm install $qwebs --save\nnpm install $qwebs-http --save\n```\n\n## Create a service.js\n\n```service.js\n\"use strict\";\n\nclass Service {\n\tconstructor() {\t\n};\n\nindex(request, response) {\n let content = {\n  text: `hello ${request.params.name}`\n };\n return response.send({ request: request, content: content });\n};\n\nexports = module.exports = Service;\n```\n\n## Define routes.json\n\n```routes.json\n{\n    \"services\": [\n        { \"name\": \"$http\", \"location\": \"qwebs-http\"},\n        { \"name\": \"$service\", \"location\": \"./service\"}\n    ],\n    \"locators\": [\n        { \"get\": \"/:name\", \"service\": \"$service\", \"method\": \"index\" },\n    ]\n}\n```\n\n## Create config.json\n\n```config.json\n{\n    \"routes\": \"./routes.json\",\n    \"http\": {\n        \"port\": 3000\n    }\n}\n```\n\n## Enjoy\n\nCreate a server.js\n\n```server.js\n\"use strict\";\n\nconst Qwebs = require(\"qwebs\");\nnew Qwebs().load();\n```\n\nRun server on http://localhost:3000\n\n```shell\nnode server.js\n```\n\n# Routing\n\nOur goal is to find the final route as fast as possible.\nWe use a tree data structure to represent all routes.\n\n  * get(route, service, method)\n  * post(route, service, method)\n  * put(route, service, method)\n  * patch(route, service, method)\n  * delete(route, service, method)\n\n```routes.json\n{\n    \"services\": [\n        { \"name\": \"$user\", \"location\": \"../services/info\"}\n    ],\n    \"locators\": [\n        { \"get\": \"/user/:id\", \"service\": \"$user\", \"method\": \"get\" },\n        { \"post\": \"/user\", \"service\": \"$user\", \"method\": \"save\" }\n    ]\n}\n```\n\n```or in javascript\nqwebs.get(\"/user/:id\", \"$users\", \"get\"); \nqwebs.post(\"/user\", \"$users\", \"save\");\n...\n```\n\n# Services\n\u003ca name=\"service\"/\u003e\n\nQwebs is deigned for POO.\nCreate service, define a route and attached them in routes.json.\nQwebs has an dependency injector for easier integration. \n\n```service.js\nclass ApplicationService {\n    //$config service is automatically injected\n    constructor($config) {\n        if ($config.verbose) console.log(\"ApplicationService created.\");\n    };\n\n    //send javascript object\n    get(request, response) {\n        let content = { message: \"Hello World\" };   \n        return response.send({ request: request, content: content });\n    };\n\n    //send stream\n    stream(request, response, reject) {\n        let stream = fs.createReadStream('file.txt')\n                       .on(\"error\", reject)           //reject Promise\n                       .pipe(new ToUpperCase())       //transform\n                       .on(\"error\", reject)           //reject Promise\n        return response.send({ request: request, stream: stream });\n    };\n};\n\nexports = module.exports = ApplicationService;\n```\n\n\u003ca name=\"di\"/\u003e\n## Dependency injection\n\nJust declare the service name in your constructor.\n\n```services/user.js\nclass UserService {\n    //Config service wil be created as a singleton and injected when UserService will be created\n    constructor($config)\n```\n\nQwebs will create your service with its dependencies.\n\n```routes.json\n{\n    \"services\": [\n        { \"name\": \"$user\", \"location\": \"../services/user\"}\n        ...\n```\n\n```on server.js\n//server.js\nqwebs.inject(\"$user\", \"./services/user\");\n```\n\n\u003ca name=\"response\"/\u003e\n## Response\n\nHttp response are automatically extended to compressed with Gzip or Deflate.\n\n  * response.send({request, statusCode, header, content, stream})\n    - [request](https://nodejs.org/api/http.html#http_class_http_clientrequest)\n    - [statusCode](http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1)\n    - [header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.2) \n    - content: js, html, json, ... *(call response.write(content))*\n    - or\n    - [stream](https://nodejs.org/api/stream.html) *(call stream.pipe(response))*\n\nYou could override this default behaviour with POO. Override the default response service and inject the new one in Qwebs.\n\n\u003ca name=\"oop\"/\u003e\n##### How override response.send ?\n```services/my-response.js\n\"use strict\";\n\nconst DataError = require(\"qwebs\").DataError;\nconst ResponseService = require(\"qwebs/lib/services/response\");\n\nclass MyResponseService extends ResponseService {\n    constructor() {\n        super();\n    };\n\n    send(response, dataToSend) {\n        return new Promise((resolve, reject) =\u003e {\n            if (dataToSend == undefined) reject(new DataError({ message: \"No data.\" }));\n\n            dataToSend.header = data.header || {};\n            dataToSend.header[\"Cache-Control\"] = \"private\";\n            dataToSend.header[\"Expires\"] = new Date(Date.now() + 3000).toUTCString();\n            return super.send(response, dataToSend).then(resolve).catch(reject);\n        });\n    };\n};\n\nexports = module.exports = MyResponseService;\n```\n\nThen replace $response service in $injector.\n\n```routes.json\n{\n    \"services\": [\n        { \"name\": \"$response\", \"location\": \"../services/my-response\"}\n    ]\n}\n```\n\n```or server.js\nqwebs.inject(\"$response\", \"./services/my-response\");\n```\n\n\u003ca name=\"disk\"/\u003e\n## Avoid disk access at runtime\n\nAll assets are loaded in memory at startup.\nUploaded images are not saved in temporary files. $qjimp service is designed to read, manipulate image stream.\n\n\u003ca name=\"bundle\"/\u003e\n## Bundle (bundle.json)\n\nYou could create your own css or js bundle without WebPack.\nQwebs includes a [Sass](https://www.npmjs.com/package/node-sass) preprocessor. You don't need to compile your sass via an external program.\n\n```bundle.json\n{\n    \"/app.js\":[\n        \"bower_components/angular-material/angular-material.js\",\n        \"bower_components/angular-route/angular-route.js\",\n        \"bower_components/angular-aria/angular-aria.js\",\n        \"bower_components/angular-sanitize/angular-sanitize.js\",\n        \"bower_components/angular-i18n/angular-locale_fr-fr.js\",\n        \"bower_components/angular-animate/angular-animate.js\",\n        \"web/app.js\"\n    ],\n    \"/app.css\":[\n        \"assets/mixins.scss\",\n        \"bower_components/angular-material/angular-material.css\",\n        \"assets/master.scss\"\n    ]   \n}\n```\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n    \u003chead\u003e\n        \u003clink rel=stylesheet type=\"text/css\" href=\"/app.css\"\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n        \u003cscript src=\"/app.js\"\u003e\u003c/script\u003e\n    \u003c/body\u003e\n\u003c/html\u003e\n```\n\n# Configuration\n\u003ca name=\"config\"/\u003e\n\n  * CORS\n\n```config.json\n{\n    \"cors\": {\n        \"enabled\": true,\n        \"allow-origin\": \"*\",\n        \"max-age\": 3600,\n        \"allow-headers\": \"Content-Type, Access-Control-Allow-Headers, Authorization\"\n    }\n}\n```\n\n\n\u003ca name=\"promise\"/\u003e\n## Promise\n\n  * Easier to read\n  * Easier to maintain in the future\n  * Easier error handling\n\n## Services\n\n  * $config: your configuration.\n  * $qwebs: qwebs instance.\n  * $injector: resolve services at runtime.\n  * $responseProxy: extand http.ServerResponse.\n  * $response: default response extension.\n  * $qjimp: convert and manipulate images.\n  \n## Others Services\n  \n  * [$http](https://www.npmjs.com/package/qwebs-http)\n  * [$https](https://www.npmjs.com/package/qwebs-https)\n  * [$http-to-https](https://www.npmjs.com/package/qwebs-http-to-https)\n  * [$mongo](https://www.npmjs.com/package/qwebs-mongo)\n  * [$authentication](https://www.npmjs.com/package/qwebs-auth-jwt)\n  * [$https](https://www.npmjs.com/package/qwebs-https)\n  * [$nodemailer](https://www.npmjs.com/package/qwebs-nodemailer)\n  * [$bitbucket](https://www.npmjs.com/package/qwebs-bitbucket-deploy)\n  * [$aws-s3](https://www.npmjs.com/package/qwebs-aws-s3)\n  * [$aws-ses](https://www.npmjs.com/package/qwebs-aws-ses)\n  * [aws api gateway](https://www.npmjs.com/package/qwebs-aws-api-gateway)\n\n## Examples\n\nTo run our examples, clone the Qwebs repo and install the dependencies.\n\n```bash\n$ git clone https://github.com/BenoitClaveau/qwebs --depth 1\n$ cd qwebs\n$ npm install\n$ cd exemples/helloworld\n$ node server.js\n```\n\n## Test\n\nTo run our tests, clone the Qwebs repo and install the dependencies.\n\n```bash\n$ git clone https://github.com/BenoitClaveau/qwebs --depth 1\n$ cd qwebs\n$ npm install\n$ cd tests\n$ node.exe \"..\\node_modules\\jasmine\\bin\\jasmine\" --verbose .\n```\n\n[npm-image]: https://img.shields.io/npm/v/qwebs.svg\n[npm-image-download]: https://img.shields.io/npm/dm/qwebs.svg\n[npm-url]: https://npmjs.org/package/qwebs\n[travis-image]: https://travis-ci.org/BenoitClaveau/qwebs.svg?branch=master\n[travis-url]: https://travis-ci.org/BenoitClaveau/qwebs\n[coveralls-image]: https://coveralls.io/repos/BenoitClaveau/qwebs/badge.svg?branch=master\u0026service=github\n[coveralls-url]: https://coveralls.io/github/BenoitClaveau/qwebs?branch=master\n[david-dm-image]: https://david-dm.org/BenoitClaveau/qwebs/status.svg\n[david-dm-url]: https://david-dm.org/BenoitClaveau/qwebs\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenoitclaveau%2Fqwebs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbenoitclaveau%2Fqwebs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenoitclaveau%2Fqwebs/lists"}