router-http 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright © 2023 Kiko Beats <josefrancisco.verdu@gmail.com> (kikobeats.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # http-router
2
+
3
+ ![Last version](https://img.shields.io/github/tag/Kikobeats/http-router.svg?style=flat-square)
4
+ [![Coverage Status](https://img.shields.io/coveralls/Kikobeats/http-router.svg?style=flat-square)](https://coveralls.io/github/Kikobeats/http-router)
5
+ [![NPM Status](https://img.shields.io/npm/dm/http-router.svg?style=flat-square)](https://www.npmjs.org/package/http-router)
6
+
7
+ An HTTP router focused in only that, similar to [express@router](https://github.com/pillarjs/router), but:
8
+
9
+ - Focused in just one thing.
10
+ - Maintained and well tested.
11
+ - Most of the API is supported.
12
+ - Smaller and portable (less 50kbs).
13
+
14
+ Don't get me wrong: The original Express router is a piece of art. I used it for years and I just considered create this library after experienced a bug that never was addressed in the stable version due to the [lack of maintenance](https://github.com/pillarjs/router/pull/60).
15
+
16
+ While I was evaluating the market for finding an alternative I found [polka](https://github.com/lukeed/polka/tree/master/packages/polka) was a good starting point for creating a replacement. This module is different than polka in some aspects:
17
+
18
+ - This module doesn't take care about the http.Server.
19
+ - This module doesn't use any of the Node.js built-in module, so it can be used in Vercel Edge Functions, Deno or CF Workers.
20
+ - This module doesn't adds `req.query` nor `req.search` (check [to-query](https://github.com/Kikobeats/to-query) for that).
21
+
22
+ In resume: this module does nothing beyond finding the correct path and matching the associated code.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ $ npm install http-router --save
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ First, you should to create a router:
33
+
34
+ ```js
35
+ const createRouter = require('http-router')
36
+
37
+ const router = createRouter((err, req, res) => {
38
+ const hasError = err !== undefined
39
+ res.statusCode = hasError ? 500 : 404
40
+ res.end(hasError ? err.message : 'Not Found')
41
+ })
42
+ ```
43
+
44
+ The router requires a final handler that will be called if an error occurred or none of the routes match.
45
+
46
+ After that, you can declare any HTTP verb route:
47
+
48
+ ### Declaring routes
49
+
50
+ ```js
51
+ /**
52
+ * Declaring multiple routes based on the HTTP verb.
53
+ */
54
+ router
55
+ .get('/', (req, res) => {
56
+ res.statusCode = 204
57
+ res.end()
58
+ })
59
+ .post('/ping', (req, res) => res.end('pong'))
60
+ .get('/greetings/:name', (req, res) => {
61
+ const { name } = req.params
62
+ res.end(`Hello, ${name}!`)
63
+ })
64
+ ```
65
+
66
+ Alternatively, you can call `.all` for associate a route for all the verbs:
67
+
68
+ ```js
69
+ /**
70
+ * Declaring a route to match all the HTTP verbs.
71
+ */
72
+ router.all('/ping', (req, res) => res.end('pong'))
73
+ ```
74
+
75
+ ### Declaring middlewares
76
+
77
+ A middleware can be declared at root level:
78
+
79
+ ```js
80
+ /**
81
+ * Declaring a middleware that will be always executed.
82
+ */
83
+ router
84
+ .use('/', (req, res, next) => {
85
+ req.timestamp = Date.now()
86
+ next()
87
+ })
88
+ ```
89
+
90
+ or for specific routes:
91
+
92
+ ```js
93
+ /**
94
+ * Declaring a middleware to execute for a certain route path.
95
+ */
96
+ router
97
+ .use('/greetings', (req, res, next) => {
98
+ req.greetings = 'Greetings'
99
+ next()
100
+ })
101
+ .get('/greetings/:username', (req, res) => {
102
+ res.end(`${req.greetings}, ${req.params.username}`)
103
+ })
104
+ ```
105
+
106
+ ### Prefixing routes
107
+
108
+ In case you need you can prefix all the routes:
109
+
110
+ ```js
111
+ routes.get('/', (req, res) => res.end('Welcome to my API!'))
112
+
113
+ /**
114
+ * Prefix all routes with the API version
115
+ */
116
+ const router = Router(final)
117
+ router
118
+ .use('/latest', routes)
119
+ .use('/v1', routes)
120
+ ```
121
+
122
+ ### Using the router
123
+
124
+ After the router has been initialized, start using it as handler in your Node.js server:
125
+
126
+ ```js
127
+ const server = http.createServer(router)
128
+ ```
129
+
130
+ ## Benchmark
131
+
132
+ The performance is essentially the same than polka, and that is almost x3 faster than express.
133
+
134
+ See [benchmark](/benchmark) sections.
135
+
136
+ ## Related
137
+
138
+ - [send-http](https://github.com/Kikobeats/send-http) – A `res.end` with data type detection.
139
+ - [http-body](https://github.com/Kikobeats/http-body) – Parse the http.IncomingMessage body into text/json/buffer.
140
+ - [http-compression](https://github.com/Kikobeats/http-compression) – Adding compression (gzip/brotli) for your HTTP server in Node.js
141
+ - [to-query](https://github.com/Kikobeats/to-query) Get query object from a request url.
142
+
143
+ ## License
144
+
145
+ **http-router** © [Kiko Beats](https://kikobeats.com), released under the [MIT](https://github.com/Kikobeats/http-router/blob/master/LICENSE.md) License.<br>
146
+ Authored and maintained by [Kiko Beats](https://kikobeats.com) with help from [contributors](https://github.com/Kikobeats/http-router/contributors).
147
+
148
+ > [kikobeats.com](https://kikobeats.com) · GitHub [Kiko Beats](https://github.com/Kikobeats) · Twitter [@Kikobeats](https://twitter.com/Kikobeats)
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "router-http",
3
+ "description": "Simple HTTP router compatible with Express",
4
+ "homepage": "https://nicedoc.io/Kikobeats/http-router",
5
+ "version": "0.0.0",
6
+ "main": "src/index.js",
7
+ "author": {
8
+ "email": "josefrancisco.verdu@gmail.com",
9
+ "name": "Kiko Beats",
10
+ "url": "https://kikobeats.com"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/Kikobeats/http-router.git"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/Kikobeats/http-router/issues"
18
+ },
19
+ "keywords": [
20
+ "app",
21
+ "http",
22
+ "http",
23
+ "middleware",
24
+ "pathname",
25
+ "rest",
26
+ "route",
27
+ "router",
28
+ "routes"
29
+ ],
30
+ "dependencies": {
31
+ "trouter": "~3.2.0"
32
+ },
33
+ "devDependencies": {
34
+ "@commitlint/cli": "latest",
35
+ "@commitlint/config-conventional": "latest",
36
+ "ava": "latest",
37
+ "c8": "latest",
38
+ "conventional-github-releaser": "latest",
39
+ "finepack": "latest",
40
+ "git-authors-cli": "latest",
41
+ "got": "11",
42
+ "nano-staged": "latest",
43
+ "npm-check-updates": "latest",
44
+ "prettier-standard": "latest",
45
+ "simple-git-hooks": "latest",
46
+ "standard": "latest",
47
+ "standard-markdown": "latest",
48
+ "standard-version": "latest"
49
+ },
50
+ "engines": {
51
+ "node": ">= 18"
52
+ },
53
+ "files": [
54
+ "src"
55
+ ],
56
+ "license": "MIT",
57
+ "commitlint": {
58
+ "extends": [
59
+ "@commitlint/config-conventional"
60
+ ]
61
+ },
62
+ "nano-staged": {
63
+ "*.js,!*.min.js,": [
64
+ "prettier-standard"
65
+ ],
66
+ "*.md": [
67
+ "standard-markdown"
68
+ ],
69
+ "package.json": [
70
+ "finepack"
71
+ ]
72
+ },
73
+ "simple-git-hooks": {
74
+ "commit-msg": "npx commitlint --edit",
75
+ "pre-commit": "npx nano-staged"
76
+ },
77
+ "scripts": {
78
+ "clean": "rm -rf node_modules",
79
+ "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
80
+ "coverage": "c8 report --reporter=text-lcov > coverage/lcov.info",
81
+ "lint": "standard-markdown README.md && standard",
82
+ "postrelease": "npm run release:tags && npm run release:github && npm publish",
83
+ "prerelease": "npm run update:check",
84
+ "pretest": "npm run lint",
85
+ "release": "standard-version -a",
86
+ "release:github": "conventional-github-releaser -p angular",
87
+ "release:tags": "git push --follow-tags origin HEAD:master",
88
+ "test": "c8 ava",
89
+ "update": "ncu -u",
90
+ "update:check": "ncu -- --error-level 2"
91
+ }
92
+ }
package/src/index.js ADDED
@@ -0,0 +1,106 @@
1
+ 'use strict'
2
+
3
+ const Trouter = require('trouter')
4
+
5
+ const requiredFinalHandler = () => {
6
+ throw new TypeError('You should to provide a final handler')
7
+ }
8
+
9
+ /**
10
+ * ensure input starts with '/'
11
+ */
12
+ const lead = route => (route.charCodeAt(0) === 47 ? route : `/${route}`)
13
+
14
+ const value = x => {
15
+ const y = x.indexOf('/', 1)
16
+ return y > 1 ? x.substring(0, y) : x
17
+ }
18
+
19
+ const mutate = (str, req) => {
20
+ req.url = req.url.substring(str.length) || '/'
21
+ req.path = req.path.substring(str.length) || '/'
22
+ }
23
+
24
+ class Router extends Trouter {
25
+ constructor (unhandler) {
26
+ super()
27
+ this.unhandler = unhandler
28
+ }
29
+
30
+ /**
31
+ * Middleware per all routes
32
+ */
33
+ #middlewares = []
34
+
35
+ /**
36
+ * Middleware for specific routes
37
+ */
38
+ #middlewaresBy = []
39
+
40
+ /**
41
+ * Middleware declaration, where the base is optional
42
+ * .use(one)
43
+ * .use('/v1', one)
44
+ * .use(one, two)
45
+ * .use('/v2', two)
46
+ */
47
+ use = (base = '/', ...fns) => {
48
+ if (typeof base === 'function') {
49
+ this.#middlewares = this.#middlewares.concat(base, fns)
50
+ } else if (base === '/') {
51
+ this.#middlewares = this.#middlewares.concat(fns)
52
+ } else {
53
+ base = lead(base)
54
+ fns.forEach(fn => {
55
+ const array = this.#middlewaresBy[base] || []
56
+ array.length > 0 || array.push((r, _, nxt) => (mutate(base, r), nxt()))
57
+ this.#middlewaresBy[base] = array.concat(fn)
58
+ })
59
+ }
60
+ return this
61
+ }
62
+
63
+ handler = (req, res, pathname) => {
64
+ pathname = pathname || req.url
65
+ let fns = []
66
+ let middlewares = this.#middlewares
67
+ const route = this.find(req.method, pathname)
68
+ const base = value((req.path = pathname))
69
+ if (this.#middlewaresBy[base] !== undefined) {
70
+ middlewares = middlewares.concat(this.#middlewaresBy[base])
71
+ }
72
+ if (route) {
73
+ fns = route.handlers
74
+ req.params = { ...req.params, ...route.params }
75
+ }
76
+ fns.push(this.unhandler)
77
+ // Exit if only a single function
78
+ let i = 0
79
+ let len = middlewares.length
80
+ const num = fns.length
81
+ if (len === i && num === 1) return fns[0](undefined, req, res)
82
+
83
+ // Otherwise loop thru all middlware
84
+ const next = err => (err ? this.unhandler(err, req, res, next) : loop())
85
+
86
+ const loop = () => {
87
+ if (res.writableEnded) return
88
+ if (i >= len) return
89
+ try {
90
+ return middlewares[i++](req, res, next)
91
+ } catch (err) {
92
+ return next(err)
93
+ }
94
+ }
95
+
96
+ middlewares = middlewares.concat(fns)
97
+ len += num
98
+ loop() // init
99
+ }
100
+ }
101
+
102
+ module.exports = (finalhandler = requiredFinalHandler()) => {
103
+ const router = new Router(finalhandler)
104
+ const handler = (req, res) => router.handler(req, res)
105
+ return Object.assign(handler, router)
106
+ }