hono 1.0.0 → 1.2.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/README.md +189 -125
- package/dist/compose.d.ts +2 -2
- package/dist/compose.js +20 -8
- package/dist/context.d.ts +4 -5
- package/dist/context.js +5 -17
- package/dist/hono.d.ts +51 -25
- package/dist/hono.js +106 -49
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/middleware/basic-auth/index.js +11 -10
- package/dist/middleware/body-parse/index.d.ts +5 -0
- package/dist/middleware/cookie/index.d.ts +1 -3
- package/dist/middleware/graphql-server/parse-body.d.ts +1 -3
- package/dist/middleware/jwt/index.d.ts +6 -0
- package/dist/middleware/jwt/index.js +49 -0
- package/dist/middleware/logger/index.js +3 -5
- package/dist/middleware/mustache/index.js +3 -9
- package/dist/router/reg-exp-router/node.d.ts +3 -0
- package/dist/router/reg-exp-router/node.js +13 -7
- package/dist/router/reg-exp-router/router.d.ts +21 -2
- package/dist/router/reg-exp-router/router.js +300 -80
- package/dist/router/reg-exp-router/trie.d.ts +4 -0
- package/dist/router/reg-exp-router/trie.js +2 -2
- package/dist/router/trie-router/node.d.ts +4 -3
- package/dist/router/trie-router/node.js +123 -55
- package/dist/router/trie-router/router.d.ts +1 -1
- package/dist/router.d.ts +4 -3
- package/dist/router.js +5 -4
- package/dist/utils/body.js +2 -2
- package/dist/utils/buffer.d.ts +1 -0
- package/dist/utils/buffer.js +9 -1
- package/dist/utils/crypto.d.ts +0 -2
- package/dist/utils/crypto.js +1 -51
- package/dist/utils/encode.d.ts +7 -0
- package/dist/utils/encode.js +105 -0
- package/dist/utils/jwt/index.d.ts +1 -0
- package/dist/utils/jwt/index.js +27 -0
- package/dist/utils/jwt/jwt.d.ts +7 -0
- package/dist/utils/jwt/jwt.js +98 -0
- package/dist/utils/jwt/types.d.ts +20 -0
- package/dist/utils/jwt/types.js +44 -0
- package/dist/utils/url.js +4 -4
- package/package.json +29 -21
package/README.md
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<a href="https://github.com/
|
|
3
|
-
<img src="https://raw.githubusercontent.com/
|
|
2
|
+
<a href="https://github.com/honojs/hono">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/honojs/hono/master/docs/images/hono-title.png" width="500" height="auto" alt="Hono"/>
|
|
4
4
|
</a>
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
7
|
<hr />
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
·
|
|
12
|
-
<a href="https://github.com/yusukebe/hono/blob/master/docs/README.ja.md">日本語</a>
|
|
13
|
-
</p>
|
|
14
|
-
|
|
15
|
-
[](https://github.com/yusukebe/hono/actions)
|
|
16
|
-
[](https://github.com/yusukebe/hono/blob/master/LICENSE)
|
|
9
|
+
[](https://github.com/honojs/hono/actions)
|
|
10
|
+
[](https://github.com/honojs/hono/blob/master/LICENSE)
|
|
17
11
|
[](https://www.npmjs.com/package/hono)
|
|
18
12
|
[](https://www.npmjs.com/package/hono)
|
|
19
13
|
[](https://www.npmjs.com/package/hono)
|
|
20
|
-
[](https://github.com/honojs/hono/pulse)
|
|
15
|
+
[](https://github.com/honojs/hono/commits/master)
|
|
22
16
|
|
|
23
|
-
Hono - _**[炎] means flame🔥 in Japanese**_ - is small, simple, and ultrafast web framework for Cloudflare Workers
|
|
17
|
+
Hono - _**[炎] means flame🔥 in Japanese**_ - is a small, simple, and ultrafast web framework for Cloudflare Workers or Service Worker based serverless such as Fastly Compute@Edge.
|
|
24
18
|
|
|
25
|
-
```
|
|
19
|
+
```ts
|
|
26
20
|
import { Hono } from 'hono'
|
|
27
21
|
const app = new Hono()
|
|
28
22
|
|
|
@@ -34,7 +28,7 @@ app.fire()
|
|
|
34
28
|
## Features
|
|
35
29
|
|
|
36
30
|
- **Ultrafast** - the router does not use linear loops.
|
|
37
|
-
- **Zero-dependencies** - using only Service Worker and Web
|
|
31
|
+
- **Zero-dependencies** - using only Service Worker and Web Standard API.
|
|
38
32
|
- **Middleware** - built-in middleware and ability to extend with your own middleware.
|
|
39
33
|
- **TypeScript** - first-class TypeScript support.
|
|
40
34
|
- **Optimized** - for Cloudflare Workers.
|
|
@@ -44,33 +38,97 @@ app.fire()
|
|
|
44
38
|
**Hono is fastest**, compared to other routers for Cloudflare Workers.
|
|
45
39
|
|
|
46
40
|
```plain
|
|
47
|
-
hono x
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
hono - trie-router(default) x 737,602 ops/sec ±3.65% (67 runs sampled)
|
|
42
|
+
hono - regexp-router x 1,188,203 ops/sec ±6.42% (60 runs sampled)
|
|
43
|
+
itty-router x 163,970 ops/sec ±3.05% (91 runs sampled)
|
|
44
|
+
sunder x 344,468 ops/sec ±0.87% (97 runs sampled)
|
|
45
|
+
worktop x 222,044 ops/sec ±2.13% (85 runs sampled)
|
|
46
|
+
Fastest is hono - regexp-router
|
|
47
|
+
✨ Done in 84.04s.
|
|
53
48
|
```
|
|
54
49
|
|
|
50
|
+
## Why so fast?
|
|
51
|
+
|
|
52
|
+
Routers used in Hono are really smart.
|
|
53
|
+
|
|
54
|
+
- **TrieRouter**(default) - Implemented with Trie tree structure.
|
|
55
|
+
- **RegExpRouter** - Match routes with one big Regex made before dispatching at once.
|
|
56
|
+
|
|
55
57
|
## Hono in 1 minute
|
|
56
58
|
|
|
57
59
|
A demonstration to create an application for Cloudflare Workers with Hono.
|
|
58
60
|
|
|
59
61
|

|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
## Not only fast
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
Hono is fast. But not only fast.
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
### Write Less, do more
|
|
66
68
|
|
|
67
|
-
You can
|
|
69
|
+
Built-in middleware make _"**Write Less, do more**"_ in reality. You can use a lot of middleware without writing code from scratch. Below are examples.
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
- [Basic Authentication](https://github.com/honojs/hono/tree/master/src/middleware/basic-auth/)
|
|
72
|
+
- [Cookie parsing / serializing](https://github.com/honojs/hono/tree/master/src/middleware/cookie/)
|
|
73
|
+
- [CORS](https://github.com/honojs/hono/tree/master/src/middleware/cors/)
|
|
74
|
+
- [ETag](https://github.com/honojs/hono/tree/master/src/middleware/etag/)
|
|
75
|
+
- [GraphQL Server](https://github.com/honojs/hono/tree/master/src/middleware/graphql-server/)
|
|
76
|
+
- [JWT Authentication](https://github.com/honojs/hono/tree/master/src/middleware/jwt/)
|
|
77
|
+
- [Logger](https://github.com/honojs/hono/tree/master/src/middleware/logger/)
|
|
78
|
+
- [Mustache template engine](https://github.com/honojs/hono/tree/master/src/middleware/mustache/) (Only for Cloudflare Workers)
|
|
79
|
+
- [JSON pretty printing](https://github.com/honojs/hono/tree/master/src/middleware/pretty-json/)
|
|
80
|
+
- [Serving static files](https://github.com/honojs/hono/tree/master/src/middleware/serve-static/) (Only for Cloudflare Workers)
|
|
81
|
+
|
|
82
|
+
To enable logger and Etag middleware with just this code.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { Hono } from 'hono'
|
|
86
|
+
import { etag } from 'hono/etag'
|
|
87
|
+
import { logger } from 'hono/logger'
|
|
88
|
+
|
|
89
|
+
const app = new Hono()
|
|
90
|
+
app.use('*', etag(), (logger())
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
And, the routing of Hono is so flexible. It's easy to construct large web applications.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { Hono, Route } from 'hono'
|
|
97
|
+
import { cors } from 'hono/cors'
|
|
98
|
+
|
|
99
|
+
const app = new Hono()
|
|
100
|
+
|
|
101
|
+
const v1 = new Route()
|
|
102
|
+
v1.get('/posts', (c) => {
|
|
103
|
+
return c.text('list pots')
|
|
104
|
+
})
|
|
105
|
+
.post('/posts', cors(), (c) => {
|
|
106
|
+
return c.text('created!', 201)
|
|
107
|
+
})
|
|
108
|
+
.get('/posts/:id', (c) => {
|
|
109
|
+
const id = c.req.param('id')
|
|
110
|
+
return c.text(`your id is ${id}`)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
app.route('/v1', v1)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Web Standard
|
|
117
|
+
|
|
118
|
+
Request and Response object used in Hono are extensions of the Web Standard [Fetch API](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API). If you are familiar with that, you don't need to know more than that.
|
|
119
|
+
|
|
120
|
+
### Developer Experience
|
|
121
|
+
|
|
122
|
+
Hono provides fine _"**Developer Experience**"_. Easy access to Request/Response thanks to the `Context` object.
|
|
123
|
+
Above all, Hono is written in TypeScript. So, Hono has _"**Types**"_!
|
|
124
|
+
|
|
125
|
+
For example, the named path parameters will be literal types.
|
|
126
|
+
|
|
127
|
+

|
|
128
|
+
|
|
129
|
+
## Install
|
|
130
|
+
|
|
131
|
+
You can install Hono from the npm registry.
|
|
74
132
|
|
|
75
133
|
```sh
|
|
76
134
|
npm install hono
|
|
@@ -80,21 +138,21 @@ npm install hono
|
|
|
80
138
|
|
|
81
139
|
An instance of `Hono` has these methods.
|
|
82
140
|
|
|
83
|
-
- app.**HTTP_METHOD**(path
|
|
84
|
-
- app.**all**(path
|
|
85
|
-
- app.**route**(path)
|
|
86
|
-
- app.**use**(path
|
|
141
|
+
- app.**HTTP_METHOD**(\[path,\] handler|middleware...)
|
|
142
|
+
- app.**all**(\[path,\] handler|middleware...)
|
|
143
|
+
- app.**route**(path, \[Route\])
|
|
144
|
+
- app.**use**(\[path,\] middleware)
|
|
87
145
|
- app.**notFound**(handler)
|
|
88
146
|
- app.**onError**(err, handler)
|
|
89
147
|
- app.**fire**()
|
|
90
148
|
- app.**fetch**(request, env, event)
|
|
91
|
-
- app.**request**(path,
|
|
149
|
+
- app.**request**(path, options)
|
|
92
150
|
|
|
93
151
|
## Routing
|
|
94
152
|
|
|
95
153
|
### Basic
|
|
96
154
|
|
|
97
|
-
```
|
|
155
|
+
```ts
|
|
98
156
|
// HTTP Methods
|
|
99
157
|
app.get('/', (c) => c.text('GET /'))
|
|
100
158
|
app.post('/', (c) => c.text('POST /'))
|
|
@@ -110,7 +168,7 @@ app.all('/hello', (c) => c.text('Any Method /hello'))
|
|
|
110
168
|
|
|
111
169
|
### Named Parameter
|
|
112
170
|
|
|
113
|
-
```
|
|
171
|
+
```ts
|
|
114
172
|
app.get('/user/:name', (c) => {
|
|
115
173
|
const name = c.req.param('name')
|
|
116
174
|
...
|
|
@@ -119,7 +177,7 @@ app.get('/user/:name', (c) => {
|
|
|
119
177
|
|
|
120
178
|
### Regexp
|
|
121
179
|
|
|
122
|
-
```
|
|
180
|
+
```ts
|
|
123
181
|
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
|
|
124
182
|
const date = c.req.param('date')
|
|
125
183
|
const title = c.req.param('title')
|
|
@@ -127,24 +185,26 @@ app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
|
|
|
127
185
|
})
|
|
128
186
|
```
|
|
129
187
|
|
|
130
|
-
###
|
|
188
|
+
### Chained route
|
|
131
189
|
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
})
|
|
140
|
-
|
|
190
|
+
```ts
|
|
191
|
+
app
|
|
192
|
+
.get('/endpoint', (c) => {
|
|
193
|
+
return c.text('GET /endpoint')
|
|
194
|
+
})
|
|
195
|
+
.post((c) => {
|
|
196
|
+
return c.text('POST /endpoint')
|
|
197
|
+
})
|
|
198
|
+
.delete((c) => {
|
|
199
|
+
return c.text('DELETE /endpoint')
|
|
200
|
+
})
|
|
141
201
|
```
|
|
142
202
|
|
|
143
203
|
### no strict
|
|
144
204
|
|
|
145
205
|
If `strict` is set false, `/hello`and`/hello/` are treated the same.
|
|
146
206
|
|
|
147
|
-
```
|
|
207
|
+
```ts
|
|
148
208
|
const app = new Hono({ strict: false }) // Default is true
|
|
149
209
|
|
|
150
210
|
app.get('/hello', (c) => c.text('/hello or /hello/'))
|
|
@@ -159,13 +219,38 @@ app.get('/fetch-url', async (c) => {
|
|
|
159
219
|
})
|
|
160
220
|
```
|
|
161
221
|
|
|
222
|
+
## Route
|
|
223
|
+
|
|
224
|
+
`Route` object enables Nested route.
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
const book = new Route()
|
|
228
|
+
|
|
229
|
+
book.get('/', (c) => c.text('List Books')) // GET /book
|
|
230
|
+
book.get('/:id', (c) => {
|
|
231
|
+
// GET /book/:id
|
|
232
|
+
const id = c.req.param('id')
|
|
233
|
+
return c.text('Get Book: ' + id)
|
|
234
|
+
})
|
|
235
|
+
book.post('/', (c) => c.text('Create Book')) // POST /book
|
|
236
|
+
|
|
237
|
+
app.route('/book', book)
|
|
238
|
+
```
|
|
239
|
+
|
|
162
240
|
## Middleware
|
|
163
241
|
|
|
242
|
+
Middleware operate after/before executing Handler. We can get `Response` before dispatching or manipulate `Response` after dispatching.
|
|
243
|
+
|
|
244
|
+
### Definition of Middleware
|
|
245
|
+
|
|
246
|
+
- Handler - should return `Response` object.
|
|
247
|
+
- Middleware - should return nothing, do `await next()`
|
|
248
|
+
|
|
164
249
|
### Built-in Middleware
|
|
165
250
|
|
|
166
251
|
Hono has built-in middleware.
|
|
167
252
|
|
|
168
|
-
```
|
|
253
|
+
```ts
|
|
169
254
|
import { Hono } from 'hono'
|
|
170
255
|
import { poweredBy } from 'hono/powered-by'
|
|
171
256
|
import { logger } from 'hono/logger'
|
|
@@ -175,6 +260,7 @@ const app = new Hono()
|
|
|
175
260
|
|
|
176
261
|
app.use('*', poweredBy())
|
|
177
262
|
app.use('*', logger())
|
|
263
|
+
|
|
178
264
|
app.use(
|
|
179
265
|
'/auth/*',
|
|
180
266
|
basicAuth({
|
|
@@ -184,13 +270,13 @@ app.use(
|
|
|
184
270
|
)
|
|
185
271
|
```
|
|
186
272
|
|
|
187
|
-
Available built-in middleware is listed on [src/middleware](https://github.com/
|
|
273
|
+
Available built-in middleware is listed on [src/middleware](https://github.com/honojs/hono/tree/master/src/middleware).
|
|
188
274
|
|
|
189
275
|
### Custom Middleware
|
|
190
276
|
|
|
191
277
|
You can write your own middleware.
|
|
192
278
|
|
|
193
|
-
```
|
|
279
|
+
```ts
|
|
194
280
|
// Custom logger
|
|
195
281
|
app.use('*', async (c, next) => {
|
|
196
282
|
console.log(`[${c.req.method}] ${c.req.url}`)
|
|
@@ -229,11 +315,11 @@ app.onError((err, c) => {
|
|
|
229
315
|
|
|
230
316
|
## Context
|
|
231
317
|
|
|
232
|
-
To handle Request and
|
|
318
|
+
To handle Request and Response, you can use `Context` object.
|
|
233
319
|
|
|
234
320
|
### c.req
|
|
235
321
|
|
|
236
|
-
```
|
|
322
|
+
```ts
|
|
237
323
|
// Get Request object
|
|
238
324
|
app.get('/hello', (c) => {
|
|
239
325
|
const userAgent = c.req.headers.get('User-Agent')
|
|
@@ -261,13 +347,15 @@ app.get('/entry/:id', (c) => {
|
|
|
261
347
|
|
|
262
348
|
### Shortcuts for Response
|
|
263
349
|
|
|
264
|
-
```
|
|
350
|
+
```ts
|
|
265
351
|
app.get('/welcome', (c) => {
|
|
266
352
|
// Set headers
|
|
267
353
|
c.header('X-Message', 'Hello!')
|
|
268
354
|
c.header('Content-Type', 'text/plain')
|
|
355
|
+
|
|
269
356
|
// Set HTTP status code
|
|
270
357
|
c.status(201)
|
|
358
|
+
|
|
271
359
|
// Return the response body
|
|
272
360
|
return c.body('Thank you for comming')
|
|
273
361
|
})
|
|
@@ -275,14 +363,13 @@ app.get('/welcome', (c) => {
|
|
|
275
363
|
|
|
276
364
|
The Response is the same as below.
|
|
277
365
|
|
|
278
|
-
```
|
|
366
|
+
```ts
|
|
279
367
|
new Response('Thank you for comming', {
|
|
280
368
|
status: 201,
|
|
281
369
|
statusText: 'Created',
|
|
282
370
|
headers: {
|
|
283
371
|
'X-Message': 'Hello',
|
|
284
372
|
'Content-Type': 'text/plain',
|
|
285
|
-
'Content-Length': '22',
|
|
286
373
|
},
|
|
287
374
|
})
|
|
288
375
|
```
|
|
@@ -291,7 +378,7 @@ new Response('Thank you for comming', {
|
|
|
291
378
|
|
|
292
379
|
Render text as `Content-Type:text/plain`.
|
|
293
380
|
|
|
294
|
-
```
|
|
381
|
+
```ts
|
|
295
382
|
app.get('/say', (c) => {
|
|
296
383
|
return c.text('Hello!')
|
|
297
384
|
})
|
|
@@ -301,7 +388,7 @@ app.get('/say', (c) => {
|
|
|
301
388
|
|
|
302
389
|
Render JSON as `Content-Type:application/json`.
|
|
303
390
|
|
|
304
|
-
```
|
|
391
|
+
```ts
|
|
305
392
|
app.get('/api', (c) => {
|
|
306
393
|
return c.json({ message: 'Hello!' })
|
|
307
394
|
})
|
|
@@ -311,7 +398,7 @@ app.get('/api', (c) => {
|
|
|
311
398
|
|
|
312
399
|
Render HTML as `Content-Type:text/html`.
|
|
313
400
|
|
|
314
|
-
```
|
|
401
|
+
```ts
|
|
315
402
|
app.get('/', (c) => {
|
|
316
403
|
return c.html('<h1>Hello! Hono!</h1>')
|
|
317
404
|
})
|
|
@@ -321,7 +408,7 @@ app.get('/', (c) => {
|
|
|
321
408
|
|
|
322
409
|
Return the `Not Found` Response.
|
|
323
410
|
|
|
324
|
-
```
|
|
411
|
+
```ts
|
|
325
412
|
app.get('/notfound', (c) => {
|
|
326
413
|
return c.notFound()
|
|
327
414
|
})
|
|
@@ -331,14 +418,14 @@ app.get('/notfound', (c) => {
|
|
|
331
418
|
|
|
332
419
|
Redirect, default status code is `302`.
|
|
333
420
|
|
|
334
|
-
```
|
|
421
|
+
```ts
|
|
335
422
|
app.get('/redirect', (c) => c.redirect('/'))
|
|
336
423
|
app.get('/redirect-permanently', (c) => c.redirect('/', 301))
|
|
337
424
|
```
|
|
338
425
|
|
|
339
426
|
### c.res
|
|
340
427
|
|
|
341
|
-
```
|
|
428
|
+
```ts
|
|
342
429
|
// Response object
|
|
343
430
|
app.use('/', (c, next) => {
|
|
344
431
|
next()
|
|
@@ -348,7 +435,7 @@ app.use('/', (c, next) => {
|
|
|
348
435
|
|
|
349
436
|
### c.event
|
|
350
437
|
|
|
351
|
-
```
|
|
438
|
+
```ts
|
|
352
439
|
// FetchEvent object
|
|
353
440
|
app.use('*', async (c, next) => {
|
|
354
441
|
c.event.waitUntil(
|
|
@@ -360,7 +447,7 @@ app.use('*', async (c, next) => {
|
|
|
360
447
|
|
|
361
448
|
### c.env
|
|
362
449
|
|
|
363
|
-
```
|
|
450
|
+
```ts
|
|
364
451
|
// Environment object for Cloudflare Workers
|
|
365
452
|
app.get('*', async c => {
|
|
366
453
|
const counter = c.env.COUNTER
|
|
@@ -372,7 +459,7 @@ app.get('*', async c => {
|
|
|
372
459
|
|
|
373
460
|
`app.fire()` do this.
|
|
374
461
|
|
|
375
|
-
```
|
|
462
|
+
```ts
|
|
376
463
|
addEventListener('fetch', (event) => {
|
|
377
464
|
event.respondWith(this.handleEvent(event))
|
|
378
465
|
})
|
|
@@ -382,17 +469,18 @@ addEventListener('fetch', (event) => {
|
|
|
382
469
|
|
|
383
470
|
`app.fetch` for Cloudflare Module Worker syntax.
|
|
384
471
|
|
|
385
|
-
```
|
|
472
|
+
```ts
|
|
386
473
|
export default {
|
|
387
474
|
fetch(request: Request, env: Env, event: FetchEvent) {
|
|
388
475
|
return app.fetch(request, env, event)
|
|
389
476
|
},
|
|
390
477
|
}
|
|
478
|
+
```
|
|
391
479
|
|
|
392
|
-
/*
|
|
393
480
|
or just do:
|
|
481
|
+
|
|
482
|
+
```ts
|
|
394
483
|
export default app
|
|
395
|
-
*/
|
|
396
484
|
```
|
|
397
485
|
|
|
398
486
|
## request
|
|
@@ -408,61 +496,35 @@ test('GET /hello is ok', async () => {
|
|
|
408
496
|
|
|
409
497
|
## Cloudflare Workers with Hono
|
|
410
498
|
|
|
411
|
-
Using [Wrangler](https://developers.cloudflare.com/workers/cli-wrangler/)
|
|
499
|
+
Using [Wrangler](https://developers.cloudflare.com/workers/cli-wrangler/), you can develop the application locally and publish it with few commands.
|
|
412
500
|
|
|
413
501
|
Let's write your first code for Cloudflare Workers with Hono.
|
|
414
502
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
### Caution
|
|
418
|
-
|
|
419
|
-
**Wrangler 1.x** does not support importing middleware. We recommend two ways:
|
|
420
|
-
|
|
421
|
-
1. Use [Wragler 2.0 Beta](https://github.com/cloudflare/wrangler2).
|
|
422
|
-
2. Build without webpack 4.x. For example, you can use esbuild. See [the starter template](https://github.com/yusukebe/hono-minimal).
|
|
423
|
-
|
|
424
|
-
---
|
|
425
|
-
|
|
426
|
-
### 1. `npm init`
|
|
427
|
-
|
|
428
|
-
Make a npm skeleton directory.
|
|
429
|
-
|
|
430
|
-
```sh
|
|
431
|
-
mkdir hono-example
|
|
432
|
-
cd hono-example
|
|
433
|
-
npm init -y
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### 2. `wrangler init`
|
|
503
|
+
### 1. `wrangler init`
|
|
437
504
|
|
|
438
505
|
Initialize as a wrangler project.
|
|
439
506
|
|
|
440
|
-
```sh
|
|
441
|
-
npx wrangler@beta init
|
|
442
507
|
```
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
```
|
|
447
|
-
Would you like to install wrangler into your package.json? (y/n) <--- n
|
|
448
|
-
Would you like to use TypeScript? (y/n) <--- n
|
|
449
|
-
Would you like to create a Worker at src/index.js? (y/n) <--- n
|
|
508
|
+
mkdir hono-example
|
|
509
|
+
cd hono-example
|
|
510
|
+
npx wrangler init -y
|
|
450
511
|
```
|
|
451
512
|
|
|
452
|
-
###
|
|
513
|
+
### 2. `npm install hono`
|
|
453
514
|
|
|
454
515
|
Install `hono` from the npm registry.
|
|
455
516
|
|
|
456
|
-
```
|
|
517
|
+
```
|
|
518
|
+
npm init -y
|
|
457
519
|
npm i hono
|
|
458
520
|
```
|
|
459
521
|
|
|
460
|
-
###
|
|
522
|
+
### 3. Write your app
|
|
461
523
|
|
|
462
|
-
Only 4 lines!!
|
|
524
|
+
Edit `src/index.ts`. Only 4 lines!!
|
|
463
525
|
|
|
464
|
-
```
|
|
465
|
-
// index.
|
|
526
|
+
```ts
|
|
527
|
+
// src/index.ts
|
|
466
528
|
import { Hono } from 'hono'
|
|
467
529
|
const app = new Hono()
|
|
468
530
|
|
|
@@ -471,47 +533,51 @@ app.get('/', (c) => c.text('Hello! Hono!'))
|
|
|
471
533
|
app.fire()
|
|
472
534
|
```
|
|
473
535
|
|
|
474
|
-
###
|
|
536
|
+
### 4. Run
|
|
475
537
|
|
|
476
538
|
Run the development server locally. Then, access `http://127.0.0.1:8787/` in your Web browser.
|
|
477
539
|
|
|
478
|
-
```
|
|
479
|
-
npx wrangler
|
|
540
|
+
```
|
|
541
|
+
npx wrangler dev
|
|
480
542
|
```
|
|
481
543
|
|
|
482
|
-
###
|
|
544
|
+
### 5. Publish
|
|
483
545
|
|
|
484
546
|
Deploy to Cloudflare. That's all!
|
|
485
547
|
|
|
486
|
-
```
|
|
487
|
-
npx wrangler
|
|
548
|
+
```
|
|
549
|
+
npx wrangler publish index.ts
|
|
488
550
|
```
|
|
489
551
|
|
|
490
552
|
## Starter template
|
|
491
553
|
|
|
492
|
-
You can start making your Cloudflare Workers application with [the starter template](https://github.com/
|
|
554
|
+
You can start making your Cloudflare Workers application with [the starter template](https://github.com/honojs/hono-minimal). It is really minimal using TypeScript, esbuild, Miniflare, and Jest.
|
|
493
555
|
|
|
494
556
|
To generate a project skelton, run this command.
|
|
495
557
|
|
|
496
|
-
```
|
|
497
|
-
|
|
558
|
+
```
|
|
559
|
+
npx create-cloudflare my-app https://github.com/honojs/hono-minimal
|
|
498
560
|
```
|
|
499
561
|
|
|
562
|
+
## Examples
|
|
563
|
+
|
|
564
|
+
- Hono Examples - <https://github.com/honojs/examples>
|
|
565
|
+
|
|
500
566
|
## Related projects
|
|
501
567
|
|
|
502
568
|
Implementation of the original router `TrieRouter` is inspired by [goblin](https://github.com/bmf-san/goblin). `RegExpRouter` is inspired by [Router::Boom](https://github.com/tokuhirom/Router-Boom). API design is inspired by [express](https://github.com/expressjs/express) and [koa](https://github.com/koajs/koa). [itty-router](https://github.com/kwhitley/itty-router), [Sunder](https://github.com/SunderJS/sunder), and [worktop](https://github.com/lukeed/worktop) are the other routers or frameworks for Cloudflare Workers.
|
|
503
569
|
|
|
504
|
-
- express <https://github.com/expressjs/express>
|
|
505
|
-
- koa <https://github.com/koajs/koa>
|
|
506
|
-
- itty-router <https://github.com/kwhitley/itty-router>
|
|
507
|
-
- Sunder <https://github.com/SunderJS/sunder>
|
|
508
|
-
- goblin <https://github.com/bmf-san/goblin>
|
|
509
|
-
- worktop <https://github.com/lukeed/worktop>
|
|
510
|
-
- Router::Boom <https://github.com/tokuhirom/Router-Boom>
|
|
570
|
+
- express - <https://github.com/expressjs/express>
|
|
571
|
+
- koa - <https://github.com/koajs/koa>
|
|
572
|
+
- itty-router - <https://github.com/kwhitley/itty-router>
|
|
573
|
+
- Sunder - <https://github.com/SunderJS/sunder>
|
|
574
|
+
- goblin - <https://github.com/bmf-san/goblin>
|
|
575
|
+
- worktop - <https://github.com/lukeed/worktop>
|
|
576
|
+
- Router::Boom - <https://github.com/tokuhirom/Router-Boom>
|
|
511
577
|
|
|
512
578
|
## Contributing
|
|
513
579
|
|
|
514
|
-
Contributions Welcome! You can contribute
|
|
580
|
+
Contributions Welcome! You can contribute in the following ways.
|
|
515
581
|
|
|
516
582
|
- Write or fix documents
|
|
517
583
|
- Write code of middleware
|
|
@@ -519,11 +585,9 @@ Contributions Welcome! You can contribute by the following way.
|
|
|
519
585
|
- Refactor the code
|
|
520
586
|
- etc.
|
|
521
587
|
|
|
522
|
-
Let's make Hono together!
|
|
523
|
-
|
|
524
588
|
## Contributors
|
|
525
589
|
|
|
526
|
-
Thanks to [all contributors](https://github.com/
|
|
590
|
+
Thanks to [all contributors](https://github.com/honojs/hono/graphs/contributors)! Especially, [@metrue](https://github.com/metrue) and [@usualoma](https://github.com/usualoma)!
|
|
527
591
|
|
|
528
592
|
## Author
|
|
529
593
|
|
package/dist/compose.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { ErrorHandler } from './hono';
|
|
2
|
-
export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler) => (context: C) => Promise<C>;
|
|
1
|
+
import type { ErrorHandler, NotFoundHandler } from './hono';
|
|
2
|
+
export declare const compose: <C>(middleware: Function[], onError?: ErrorHandler, onNotFound?: NotFoundHandler) => (context: C, next?: Function) => Promise<C>;
|
package/dist/compose.js
CHANGED
|
@@ -3,26 +3,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.compose = void 0;
|
|
4
4
|
const context_1 = require("./context");
|
|
5
5
|
// Based on the code in the MIT licensed `koa-compose` package.
|
|
6
|
-
const compose = (middleware, onError) => {
|
|
7
|
-
return
|
|
6
|
+
const compose = (middleware, onError, onNotFound) => {
|
|
7
|
+
return async (context, next) => {
|
|
8
8
|
let index = -1;
|
|
9
9
|
return dispatch(0);
|
|
10
10
|
async function dispatch(i) {
|
|
11
|
-
if (i === middleware.length) {
|
|
12
|
-
return context;
|
|
13
|
-
}
|
|
14
11
|
if (i <= index) {
|
|
15
12
|
return Promise.reject(new Error('next() called multiple times'));
|
|
16
13
|
}
|
|
17
|
-
|
|
14
|
+
let handler = middleware[i];
|
|
18
15
|
index = i;
|
|
16
|
+
if (i === middleware.length)
|
|
17
|
+
handler = next;
|
|
18
|
+
if (handler === undefined) {
|
|
19
|
+
if (context instanceof context_1.Context && context.res === undefined) {
|
|
20
|
+
context.res = onNotFound(context);
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve(context);
|
|
23
|
+
}
|
|
19
24
|
return Promise.resolve(handler(context, dispatch.bind(null, i + 1)))
|
|
20
|
-
.then(() => {
|
|
25
|
+
.then(async (res) => {
|
|
26
|
+
// If handler return Response like `return c.text('foo')`
|
|
27
|
+
if (res && context instanceof context_1.Context) {
|
|
28
|
+
context.res = res;
|
|
29
|
+
dispatch(i + 1); // <--- Call next()
|
|
30
|
+
}
|
|
21
31
|
return context;
|
|
22
32
|
})
|
|
23
33
|
.catch((err) => {
|
|
24
34
|
if (onError && context instanceof context_1.Context) {
|
|
25
|
-
|
|
35
|
+
if (err instanceof Error) {
|
|
36
|
+
context.res = onError(err, context);
|
|
37
|
+
}
|
|
26
38
|
return context;
|
|
27
39
|
}
|
|
28
40
|
else {
|
package/dist/context.d.ts
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
import type { StatusCode } from './utils/http-status';
|
|
3
3
|
declare type Headers = Record<string, string>;
|
|
4
4
|
declare type Data = string | ArrayBuffer | ReadableStream;
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
export declare class Context<RequestParamKeyType = string> {
|
|
5
|
+
export declare type Env = Record<string, any>;
|
|
6
|
+
export declare class Context<RequestParamKeyType = string, E = Env> {
|
|
8
7
|
req: Request<RequestParamKeyType>;
|
|
9
8
|
res: Response;
|
|
10
|
-
env:
|
|
9
|
+
env: E;
|
|
11
10
|
event: FetchEvent;
|
|
12
11
|
private _headers;
|
|
13
12
|
private _status;
|
|
@@ -18,7 +17,7 @@ export declare class Context<RequestParamKeyType = string> {
|
|
|
18
17
|
notFound: () => Response | Promise<Response>;
|
|
19
18
|
constructor(req: Request<RequestParamKeyType>, opts?: {
|
|
20
19
|
res: Response;
|
|
21
|
-
env:
|
|
20
|
+
env: E;
|
|
22
21
|
event: FetchEvent;
|
|
23
22
|
});
|
|
24
23
|
private initRequest;
|