Skip to content

Commit e8179df

Browse files
committed
v0.0.1 ;)
1 parent 05ac457 commit e8179df

File tree

6 files changed

+241
-2
lines changed

6 files changed

+241
-2
lines changed

README.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,36 @@
1-
# 0http-bun
2-
Bun-based HTTP framework inspired by 0http
1+
# Introduction
2+
Experimental, bun-based HTTP framework inspired by 0http!
3+
4+
## Usage
5+
```js
6+
const http = require('0http-bun')
7+
8+
const { router } = http({})
9+
router.use((req, next) => {
10+
req.ctx = {
11+
engine: 'bun'
12+
}
13+
14+
return next()
15+
})
16+
router.get('/:id', async (req) => {
17+
return Response.json(req.params)
18+
})
19+
router.post('/', async (req) => {
20+
return new Response('POST')
21+
})
22+
router.delete('/:id', async (req) => {
23+
return Response.json(req.params, {
24+
status: 200
25+
})
26+
})
27+
28+
module.exports = {
29+
port: 3000,
30+
fetch: (request) => router.lookup(request)
31+
}
32+
```
33+
34+
# Support / Donate 💚
35+
You can support the maintenance of this project:
36+
- PayPal: https://www.paypal.me/kyberneees

demos/basic.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* global Response */
2+
const http = require('../index')
3+
4+
const { router } = http({})
5+
router.use((req, next) => {
6+
req.ctx = {
7+
engine: 'bun'
8+
}
9+
10+
return next()
11+
})
12+
router.get('/:id', async (req) => {
13+
return Response.json(req.params)
14+
})
15+
router.post('/', async (req) => {
16+
return new Response('POST')
17+
})
18+
router.delete('/:id', async (req) => {
19+
return Response.json(req.params, {
20+
status: 200
21+
})
22+
})
23+
24+
module.exports = {
25+
port: 3000,
26+
fetch: (request) => router.lookup(request)
27+
}

index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = (config = {}) => {
2+
const router = config.router || require('./lib/router/sequential')(config)
3+
4+
return {
5+
router
6+
}
7+
}

lib/next.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module.exports = function next (middlewares, req, index, routers = {}, defaultRoute, errorHandler) {
2+
const middleware = middlewares[index]
3+
if (!middleware) {
4+
return defaultRoute(req)
5+
}
6+
7+
function step (err) {
8+
if (err) {
9+
return errorHandler(err, req)
10+
} else {
11+
return next(middlewares, req, index + 1, routers, defaultRoute, errorHandler)
12+
}
13+
}
14+
15+
try {
16+
if (middleware.id) {
17+
// nested routes support
18+
const pattern = routers[middleware.id]
19+
if (pattern) {
20+
req.preRouterPath = req.path
21+
22+
req.path = req.path.replace(pattern, '')
23+
if (!req.path.startsWith('/')) {
24+
req.path = '/' + req.path
25+
}
26+
}
27+
28+
return middleware.lookup(req, step)
29+
} else {
30+
return middleware(req, step)
31+
}
32+
} catch (err) {
33+
return errorHandler(err, req)
34+
}
35+
}

lib/router/sequential.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/* global Response */
2+
3+
const Trouter = require('trouter')
4+
const next = require('./../next')
5+
const LRU = require('lru-cache')
6+
const { parse } = require('regexparam')
7+
8+
module.exports = (config = {}) => {
9+
if (config.defaultRoute === undefined) {
10+
config.defaultRoute = (req) => {
11+
const res = new Response(null, {
12+
status: 404
13+
})
14+
15+
return res
16+
}
17+
}
18+
if (config.errorHandler === undefined) {
19+
config.errorHandler = (err, req) => {
20+
const res = new Response(err.message, {
21+
status: 500
22+
})
23+
24+
return res
25+
}
26+
}
27+
if (config.cacheSize === undefined) {
28+
config.cacheSize = 1000
29+
}
30+
if (config.id === undefined) {
31+
config.id = (Date.now().toString(36) + Math.random().toString(36).substring(2, 5)).toUpperCase()
32+
}
33+
34+
const routers = {}
35+
const isCacheEnabled = config.cacheSize > 0
36+
const cache = isCacheEnabled ? new LRU({ max: config.cacheSize }) : null
37+
const router = new Trouter()
38+
router.id = config.id
39+
40+
const _use = router.use
41+
42+
router.use = (prefix, ...middlewares) => {
43+
if (typeof prefix === 'function') {
44+
middlewares = [prefix, ...middlewares]
45+
prefix = '/'
46+
}
47+
_use.call(router, prefix, middlewares)
48+
49+
if (middlewares[0].id) {
50+
// caching router -> pattern relation for urls pattern replacement
51+
const { pattern } = parse(prefix, true)
52+
routers[middlewares[0].id] = pattern
53+
}
54+
55+
return this
56+
}
57+
58+
router.lookup = async (req, step) => {
59+
const url = new URL(req.url)
60+
req.path = url.pathname || '/'
61+
req.query = url.queryparams
62+
req.search = url.search
63+
req.hostname = url.hostname
64+
65+
let match
66+
if (isCacheEnabled) {
67+
const reqCacheKey = req.method + req.path
68+
match = cache.get(reqCacheKey)
69+
if (!match) {
70+
match = router.find(req.method, req.path)
71+
cache.set(reqCacheKey, match)
72+
}
73+
} else {
74+
match = router.find(req.method, req.path)
75+
}
76+
77+
if (match.handlers.length !== 0) {
78+
const middlewares = [...match.handlers]
79+
if (step !== undefined) {
80+
// router is being used as a nested router
81+
middlewares.push((req, next) => {
82+
req.path = req.preRouterPath
83+
84+
delete req.preRouterPath
85+
86+
return step()
87+
})
88+
}
89+
90+
if (!req.params) {
91+
req.params = {}
92+
}
93+
Object.assign(req.params, match.params)
94+
95+
return next(middlewares, req, 0, routers, config.defaultRoute, config.errorHandler)
96+
} else {
97+
return config.defaultRoute(req)
98+
}
99+
}
100+
101+
router.on = (method, pattern, ...handlers) => router.add(method, pattern, handlers)
102+
103+
return router
104+
}

package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "0http-bun",
3+
"version": "0.0.1",
4+
"description": "0http alternative for Bun",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"dependencies": {
10+
"lru-cache": "^7.10.1",
11+
"regexparam": "^2.0.0",
12+
"trouter": "^3.2.0"
13+
},
14+
"repository": {
15+
"type": "git",
16+
"url": "git+https://github.com/BackendStack21/0http-bun.git"
17+
},
18+
"keywords": [
19+
"http",
20+
"server",
21+
"rest",
22+
"api",
23+
"web",
24+
"bun"
25+
],
26+
"author": "Rolando Santamaria Maso <[email protected]>",
27+
"license": "MIT",
28+
"bugs": {
29+
"url": "https://github.com/BackendStack21/0http-bun/issues"
30+
},
31+
"homepage": "https://github.com/BackendStack21/0http-bun#readme"
32+
}

0 commit comments

Comments
 (0)