{"id":19326938,"url":"https://github.com/panosoft/https-server","last_synced_at":"2025-02-24T06:22:18.899Z","repository":{"id":66288791,"uuid":"50367669","full_name":"panosoft/https-server","owner":"panosoft","description":null,"archived":false,"fork":false,"pushed_at":"2016-02-04T22:44:21.000Z","size":27,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-23T04:27:29.133Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/panosoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-25T17:24:22.000Z","updated_at":"2016-01-25T18:13:25.000Z","dependencies_parsed_at":"2023-04-27T06:41:55.045Z","dependency_job_id":null,"html_url":"https://github.com/panosoft/https-server","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panosoft%2Fhttps-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panosoft%2Fhttps-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panosoft%2Fhttps-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/panosoft%2Fhttps-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/panosoft","download_url":"https://codeload.github.com/panosoft/https-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240427773,"owners_count":19799560,"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":[],"created_at":"2024-11-10T02:15:27.428Z","updated_at":"2025-02-24T06:22:18.873Z","avatar_url":"https://github.com/panosoft.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Https Server\n\n\u003e An HTTPS server with a built-in router.\n\n[![npm version](https://img.shields.io/npm/v/@panosoft/https-server.svg)](https://www.npmjs.com/package/@panosoft/https-server)\n[![Travis](https://img.shields.io/travis/panosoft/https-server.svg)](https://travis-ci.org/panosoft/https-server)\n\nThis module can be used to create an HTTPS server that can route requests to a pre-defined set of handlers. It also provides an interface that makes it trivial to run such a server from the command line.\n\nEach request received is assigned a unique id that is included in all associated log entries and is returned to the requester in the `Request-Id` header of the response.\n\nIf a request is received for an unhandled pathname or method the server will log the occurrence and respond with the proper HTTP response codes.\n\nSimilarly, if an error is encountered while handling a defined route, the occurrence will be logged and the proper HTTP response will be sent to the requester.\n\n# Installation\n\n```sh\nnpm install @panosoft/https-server\n```\n\n# Usage\n\nThe [`cli`](#cli) method can be used to quickly create a server that can be run from the command line:\n\n```js\n#! /usr/bin/env node\n\nconst HttpsServer = require('@panosoft/https-server');\n\nconst packageFilename = '/path/to/top-level/pacakge.json';\nconst routes = {\n  '/': {\n    GET: (request, response, log) =\u003e response.end('Hello World')\n  }\n};\n\nHttpsServer.cli(packageFilename, routes);\n```\n\nOr, the API can be used directly:\n\n```js\nconst bunyan = require('bunyan');\nconst fs = require('fs');\nconst HttpsServer = require('@panosoft/https-server');\n\nconst options = {\n  key: fs.readFileSync('path/to/key.pem'),\n  cert: fs.readFileSync('path/to/cert.pem'),\n  logger: bunyan.createLogger({name: 'server'})\n};\nconst routes = {\n  '/': {\n    GET: (request, response, log) =\u003e response.end('Hello World')\n  }\n};\nconst server = HttpsServer.create(options, routes);\n\nyield server.listen(8443, '127.0.0.1');\nserver.address();\nyield server.connections();\nyield server.close();\n```\n\n\u003ca name=\"routes\"\u003e\u003c/a\u003e\n# Routes\n\nAn object that determines how requests will be routed and handled. It has the following structure:\n\n```js\n{\n  \u003cpathname\u003e : {\n    \u003cmethod\u003e: \u003chandler\u003e,\n    ...\n  },\n  ...\n}\n```\n\nWhere:\n\n- `pathname` - {String} Any valid path.\n\n- `method` - {String} Any valid HTTP method.\n\n- `handler` - {Function}\n\n  A function to be called when the specified pathname and method are requested.\n\n  This function will be called with the `request` and `response` streams generated by Node's [`https.Server`](https://nodejs.org/api/https.html#https_class_https_server) along with a Bunyan logger that includes the serialized request with every log entry.\n\n  This function should handle the entire request, write any necessary log entries, and call `response.end()` when it has completed.\n\n  This function will be run asynchronously if it returns a `Promise`. Otherwise, it will be run synchronously.\n\n  In the case of synchronous handlers, when an error is encountered, it should be thrown.\n\n  In the case of asynchronous handlers, when an error is encountered the returned `Promise` should be rejected with the error.\n\n  All handler errors will be automatically be logged by the server and an HTTP error response will automatically be sent to the requester.\n\n__Example__\n\n```js\nconst routes = {\n  '/': {\n    GET: (request, response, log) =\u003e {}\n  },\n  '/user': {\n    GET:(request, response, log) =\u003e {},\n    POST: (request, response, log) =\u003e {},\n    DELETE: (request, response, log) =\u003e {}    \n  }\n};\n```\n\n# Error Responses\n\n## Path Not Found\n\nWhen a requested path is not defined in `Routes`, the following error response is sent to the requester:\n\n- Status Code: `404`\n- Headers:\n  - `Request-Id` - {String} The unique id assigned to the associated request.\n  - `Content-Type` - `'application/json'`\n- Body:\n  - `error` - `'${pathname} not found'`\n\n## Method Not Defined\n\nWhen an undefined method for a path defined in `Routes` is requested, the following error response is sent to the requester:\n\n- Status Code: `405`\n- Headers:\n  - `Request-Id` - {String} The unique id assigned to the associated request.\n  - `Content-Type` - `'application/json'`\n  - `Allow` - {String} A comma separated list of valid methods for the requested path.\n- Body:\n  - `error` - `'${method} not allowed for ${pathname}'`\n\n## Internal Server error\n\nWhen an error is thrown or a returned promise is rejected by a route handler, the following error response is sent to the requester:\n\n- Status Code: `500`\n- Headers:\n  - `Request-Id` - {String} The unique id assigned to the associated request.\n  - `Content-Type` - `'application/json'`\n- Body:\n  - `error` - {String} The associated error message.\n\n# API\n\n## cli ( packageFilename , routes )\n\nRun the server as a node command line program.\n\nHelp and version commands are automatically generated using the contents of the `package.json` file found at the provided path.\n\nLog entries are written to `stdout` and `stderr` as appropriate.\n\nAlso, the following process events are also handled gracefully and appropriately (i.e. open connections are closed and appropriate exit codes are returned by the process):\n\n- `SIGINT`\n\n- `SIGTERM`\n\n- `unhandledRejection`\n\n- `uncaughtException`\n\nWhen run as a command the following interface is available:\n\n```sh\nUsage: command-name --key \u003cpath\u003e --cert \u003cpath\u003e [options]\n\nDescription from package.json ...\n\nOptions:\n\n  -h, --help                    output usage information\n  -V, --version                 output the version number\n  -k, --key   \u003cpath\u003e            Path to the private key of the server in PEM format.\n  -c, --cert  \u003cpath\u003e            Path to the certificate key of the server in PEM format.\n  -p, --port  \u003cport\u003e            The port to accept connections on. Default: 8443.\n  -i, --interface  \u003cinterface\u003e  The interface to accept connections on. Default: 0.0.0.0.\n```\n\n__Arguments__\n\n- `packageFilename` - {String} A path to the `package.json` for the module calling this function.\n\n- `routes` - {[Routes](#routes)} A routes object.\n\n__Example__\n\n```js\n#! /usr/bin/env node\n\nconst HttpsServer = require('@panosoft/https-server');\n\nconst packageFilename = '/path/to/top-level/pacakge.json';\nconst routes = {\n  '/': { GET: (request, response, log) =\u003e response.end('Hello World') }\n};\n\nHttpsServer.cli(packageFilename, routes);\n```\n\n## create ( options , routes )\n\nCreate a new instance of HttpsServer.\n\n__Arguments__\n\n- `options`\n\n  - `key` - (Required) {String} The private key of the server in PEM format.\n\n  - `cert` - (Required) {String} The certificate key of the server in PEM format.\n\n  - `logger` - {Bunyan Logger} An instance of a [Bunyan]() logger.\n\n  - ... any other supported Node [https.Server]() options\n\n- `routes` - {[Routes](#routes)} A routes object.\n\n__Example__\n\n```js\nconst options = {\n  key: fs.readFileSync('path/to/key.pem'),\n  cert: fs.readFileSync('path/to/cert.pem'),\n  logger: bunyan.createLogger({name: 'server'})\n};\nconst routes = {\n  '/': { GET: (request, response, log) =\u003e response.end('Hello World') }\n};\nconst server = HttpsServer.create(options, routes);\n```\n\n## listen ( ... )\n\nA thin wrapper around Node's [server.listen](https://nodejs.org/api/https.html#https_server_listen_handle_callback) method that returns a `Promise` instead of taking a callback.\n\n## address ( )\n\nEquivalent to Node's [server.address](https://nodejs.org/api/net.html#net_server_address) method.\n\n## connections ( )\n\nA thin wrapper around Node's [server.getConnections](https://nodejs.org/api/net.html#net_server_getconnections_callback) method that returns a `Promise` instead of taking a callback.\n\n## close ( )\n\nA thin wrapper around Node's [server.close](https://nodejs.org/api/https.html#https_server_close_callback) method that returns a `Promise` instead of taking a callback.\n\nAlso, this method differs from Node's [server.close](https://nodejs.org/api/https.html#https_server_close_callback) in that it will not return an error if it is called while the server is not listening.\n\n## test.startServer ( filename [, options] )\n\nA helper function that makes it simple to test cli servers that use the `cli` method.\n\nThis function spawns the cli server in a child process. It returns a `Promise` that is fullfilled with a reference to the server process once the server has started successfully. If an error is encountered, the promise will be rejected with the error.\n\n__Arguments__\n\n- `filename` - {String} File path to an executable file that calls the `cli` method.\n\n- `options` - {Object} An object of server options.\n\n    - `port` - {Number} The port to start the server on.\n\n    - `interface` - {String} The interface to start the server on.\n\n__Example__\n\nAssuming we have and executable file at `path/to/executable.js` with the following contents:\n\n```js\n#! /usr/bin/env node\n\nconst HttpsServer = require('@panosoft/https-server');\nconst path = require('path');\n\nconst packageFilename = path.resolve(__dirname, '../package.json');\nconst routes = { '/': { 'POST': (req, res, log) =\u003e res.end('root') }};\nHttpsServer.cli(packageFilename, routes);\n```\n\nThen we can use the `test.startServer` method to run this executable file and know when the server has started:\n\n```js\nconst co = require('co');\nconst HttpsServer = require('@panosoft/https-server');\n\nco(function * () {\n  const filename = `path/to/executable.js`;\n  const server = yield HttpsServer.test.startServer(filename);\n  // make requests ...\n  server.kill();\n})\n```\n\n## test.request ( pathname , method , headers , data )\n\nA helper function that makes it simple to make requests to a test instance of https-server being run with `test.startServer`. This method handles making requests with the self-signed TLS certificate used by `test.startServer`.\n\nThis method makes a request that will recognize the the self-signed TLS certificate used by `test.startServer` as valid. It returns a `Promise` that is fulfilled with the completed response that includes the response body at `response.body`.\n\n__Arguments__\n\n- `pathname` - {String} The pathname to request.\n\n- `method` - {String} The HTTP method to use. Defaults to `GET`.\n\n- `headers` - {Object} The headers to include with the request. Defaults to `{}`.\n\n- `data` - {\\*} The data to send along with the request. Defaults to `null`.\n\n__Example__\n\nContinuing the `test.startServer` example above ...\n\n```js\nconst co = require('co');\nconst HttpsServer = require('@panosoft/https-server');\n\nco(function * () {\n  const filename = `path/to/executable.js`;\n  const server = yield HttpsServer.test.startServer(filename);\n\n  const pathname = '/';\n  const method = 'POST';\n  const headers = { 'Content-Type': 'application/json' };\n  const data = JSON.stringify({ a: 1 });\n  const response = yield request( pathname, method, headers, data);\n  console.log(response.body.toString('utf8')); //=\u003e 'root'\n\n  server.kill();\n})\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanosoft%2Fhttps-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpanosoft%2Fhttps-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpanosoft%2Fhttps-server/lists"}