hono 1.1.1 → 1.2.2
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 +126 -117
- package/dist/compose.d.ts +2 -2
- package/dist/compose.js +20 -8
- package/dist/compose.test.d.ts +1 -0
- package/dist/compose.test.js +511 -0
- package/dist/context.d.ts +8 -1
- package/dist/context.js +27 -37
- package/dist/context.test.d.ts +1 -0
- package/dist/context.test.js +127 -0
- package/dist/hono.d.ts +44 -21
- package/dist/hono.js +74 -43
- package/dist/hono.test.d.ts +1 -0
- package/dist/hono.test.js +592 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/middleware/basic-auth/index.js +2 -2
- package/dist/middleware/basic-auth/index.test.d.ts +1 -0
- package/dist/middleware/basic-auth/index.test.js +119 -0
- package/dist/middleware/body-parse/index.test.d.ts +1 -0
- package/dist/middleware/body-parse/index.test.js +59 -0
- package/dist/middleware/cookie/index.d.ts +1 -1
- package/dist/middleware/cookie/index.test.d.ts +1 -0
- package/dist/middleware/cookie/index.test.js +54 -0
- package/dist/middleware/cors/index.test.d.ts +1 -0
- package/dist/middleware/cors/index.test.js +59 -0
- package/dist/middleware/etag/index.test.d.ts +1 -0
- package/dist/middleware/etag/index.test.js +45 -0
- package/dist/middleware/graphql-server/index.js +1 -1
- package/dist/middleware/graphql-server/index.test.d.ts +1 -0
- package/dist/middleware/graphql-server/index.test.js +480 -0
- package/dist/middleware/graphql-server/parse-body.test.d.ts +1 -0
- package/dist/middleware/graphql-server/parse-body.test.js +57 -0
- package/dist/middleware/jwt/index.js +9 -11
- package/dist/middleware/jwt/index.test.d.ts +1 -0
- package/dist/middleware/jwt/index.test.js +51 -0
- package/dist/middleware/logger/index.test.d.ts +1 -0
- package/dist/middleware/logger/index.test.js +49 -0
- package/dist/middleware/mustache/index.test.d.ts +1 -0
- package/dist/middleware/mustache/index.test.js +49 -0
- package/dist/middleware/powered-by/index.test.d.ts +1 -0
- package/dist/middleware/powered-by/index.test.js +15 -0
- package/dist/middleware/pretty-json/index.test.d.ts +1 -0
- package/dist/middleware/pretty-json/index.test.js +28 -0
- package/dist/middleware/serve-static/index.test.d.ts +1 -0
- package/dist/middleware/serve-static/index.test.js +58 -0
- package/dist/router/reg-exp-router/index.d.ts +1 -1
- package/dist/router/reg-exp-router/index.js +1 -1
- 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 +301 -81
- package/dist/router/reg-exp-router/router.test.d.ts +1 -0
- package/dist/router/reg-exp-router/router.test.js +212 -0
- package/dist/router/reg-exp-router/trie.d.ts +7 -3
- package/dist/router/reg-exp-router/trie.js +3 -3
- package/dist/router/trie-router/index.d.ts +1 -1
- package/dist/router/trie-router/index.js +1 -1
- package/dist/router/trie-router/node.d.ts +4 -3
- package/dist/router/trie-router/node.js +123 -55
- package/dist/router/trie-router/node.test.d.ts +1 -0
- package/dist/router/trie-router/node.test.js +351 -0
- package/dist/router/trie-router/router.d.ts +2 -2
- package/dist/router/trie-router/router.js +1 -1
- package/dist/router/trie-router/router.test.d.ts +1 -0
- package/dist/router/trie-router/router.test.js +98 -0
- package/dist/router.d.ts +4 -3
- package/dist/router.js +5 -4
- package/dist/utils/body.js +2 -2
- package/dist/utils/body.test.d.ts +1 -0
- package/dist/utils/body.test.js +45 -0
- package/dist/utils/buffer.js +1 -1
- package/dist/utils/buffer.test.d.ts +1 -0
- package/dist/utils/buffer.test.js +36 -0
- package/dist/utils/cloudflare.test.d.ts +1 -0
- package/dist/utils/cloudflare.test.js +42 -0
- package/dist/utils/crypto.test.d.ts +1 -0
- package/dist/utils/crypto.test.js +15 -0
- package/dist/utils/encode.test.d.ts +1 -0
- package/dist/utils/encode.test.js +54 -0
- package/dist/utils/http-status.test.d.ts +1 -0
- package/dist/utils/http-status.test.js +8 -0
- package/dist/utils/jwt/jwt.test.d.ts +1 -0
- package/dist/utils/jwt/jwt.test.js +171 -0
- package/dist/utils/jwt/types.test.d.ts +1 -0
- package/dist/utils/jwt/types.test.js +12 -0
- package/dist/utils/mime.test.d.ts +1 -0
- package/dist/utils/mime.test.js +13 -0
- package/dist/utils/url.js +4 -4
- package/dist/utils/url.test.d.ts +1 -0
- package/dist/utils/url.test.js +87 -0
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -6,12 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
<hr />
|
|
8
8
|
|
|
9
|
-
<p>
|
|
10
|
-
<a href="https://github.com/honojs/hono/blob/master/README.md">English</a>
|
|
11
|
-
·
|
|
12
|
-
<a href="https://github.com/honojs/hono/blob/master/docs/README.ja.md">日本語</a>
|
|
13
|
-
</p>
|
|
14
|
-
|
|
15
9
|
[](https://github.com/honojs/hono/actions)
|
|
16
10
|
[](https://github.com/honojs/hono/blob/master/LICENSE)
|
|
17
11
|
[](https://www.npmjs.com/package/hono)
|
|
@@ -20,9 +14,9 @@
|
|
|
20
14
|
[](https://github.com/honojs/hono/pulse)
|
|
21
15
|
[](https://github.com/honojs/hono/commits/master)
|
|
22
16
|
|
|
23
|
-
Hono - _**[炎] means flame🔥 in Japanese**_ - is a 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,24 +28,32 @@ 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
|
-
- **Optimized** - for Cloudflare Workers
|
|
34
|
+
- **Optimized** - for Cloudflare Workers.
|
|
41
35
|
|
|
42
36
|
## Benchmark
|
|
43
37
|
|
|
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.
|
|
@@ -77,20 +79,47 @@ Built-in middleware make _"**Write Less, do more**"_ in reality. You can use a l
|
|
|
77
79
|
- [JSON pretty printing](https://github.com/honojs/hono/tree/master/src/middleware/pretty-json/)
|
|
78
80
|
- [Serving static files](https://github.com/honojs/hono/tree/master/src/middleware/serve-static/) (Only for Cloudflare Workers)
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
To enable logger and Etag middleware with just this code.
|
|
81
83
|
|
|
82
|
-
```
|
|
84
|
+
```ts
|
|
83
85
|
import { Hono } from 'hono'
|
|
84
|
-
import {
|
|
86
|
+
import { etag } from 'hono/etag'
|
|
85
87
|
import { logger } from 'hono/logger'
|
|
86
88
|
|
|
87
89
|
const app = new Hono()
|
|
88
|
-
app.use('*',
|
|
90
|
+
app.use('*', etag(), logger())
|
|
91
|
+
```
|
|
92
|
+
|
|
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)
|
|
89
114
|
```
|
|
90
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
|
+
|
|
91
120
|
### Developer Experience
|
|
92
121
|
|
|
93
|
-
|
|
122
|
+
Hono provides fine _"**Developer Experience**"_. Easy access to Request/Response thanks to the `Context` object.
|
|
94
123
|
Above all, Hono is written in TypeScript. So, Hono has _"**Types**"_!
|
|
95
124
|
|
|
96
125
|
For example, the named path parameters will be literal types.
|
|
@@ -101,12 +130,6 @@ For example, the named path parameters will be literal types.
|
|
|
101
130
|
|
|
102
131
|
You can install Hono from the npm registry.
|
|
103
132
|
|
|
104
|
-
```sh
|
|
105
|
-
yarn add hono
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
or
|
|
109
|
-
|
|
110
133
|
```sh
|
|
111
134
|
npm install hono
|
|
112
135
|
```
|
|
@@ -115,21 +138,21 @@ npm install hono
|
|
|
115
138
|
|
|
116
139
|
An instance of `Hono` has these methods.
|
|
117
140
|
|
|
118
|
-
- app.**HTTP_METHOD**(\[path,\] handler)
|
|
119
|
-
- app.**all**(\[path,\] handler)
|
|
120
|
-
- app.**route**(path)
|
|
141
|
+
- app.**HTTP_METHOD**(\[path,\] handler|middleware...)
|
|
142
|
+
- app.**all**(\[path,\] handler|middleware...)
|
|
143
|
+
- app.**route**(path, \[Route\])
|
|
121
144
|
- app.**use**(\[path,\] middleware)
|
|
122
145
|
- app.**notFound**(handler)
|
|
123
146
|
- app.**onError**(err, handler)
|
|
124
147
|
- app.**fire**()
|
|
125
148
|
- app.**fetch**(request, env, event)
|
|
126
|
-
- app.**request**(path,
|
|
149
|
+
- app.**request**(path, options)
|
|
127
150
|
|
|
128
151
|
## Routing
|
|
129
152
|
|
|
130
153
|
### Basic
|
|
131
154
|
|
|
132
|
-
```
|
|
155
|
+
```ts
|
|
133
156
|
// HTTP Methods
|
|
134
157
|
app.get('/', (c) => c.text('GET /'))
|
|
135
158
|
app.post('/', (c) => c.text('POST /'))
|
|
@@ -145,7 +168,7 @@ app.all('/hello', (c) => c.text('Any Method /hello'))
|
|
|
145
168
|
|
|
146
169
|
### Named Parameter
|
|
147
170
|
|
|
148
|
-
```
|
|
171
|
+
```ts
|
|
149
172
|
app.get('/user/:name', (c) => {
|
|
150
173
|
const name = c.req.param('name')
|
|
151
174
|
...
|
|
@@ -154,7 +177,7 @@ app.get('/user/:name', (c) => {
|
|
|
154
177
|
|
|
155
178
|
### Regexp
|
|
156
179
|
|
|
157
|
-
```
|
|
180
|
+
```ts
|
|
158
181
|
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
|
|
159
182
|
const date = c.req.param('date')
|
|
160
183
|
const title = c.req.param('title')
|
|
@@ -164,7 +187,7 @@ app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
|
|
|
164
187
|
|
|
165
188
|
### Chained route
|
|
166
189
|
|
|
167
|
-
```
|
|
190
|
+
```ts
|
|
168
191
|
app
|
|
169
192
|
.get('/endpoint', (c) => {
|
|
170
193
|
return c.text('GET /endpoint')
|
|
@@ -177,24 +200,11 @@ app
|
|
|
177
200
|
})
|
|
178
201
|
```
|
|
179
202
|
|
|
180
|
-
### Nested route
|
|
181
|
-
|
|
182
|
-
```js
|
|
183
|
-
const book = app.route('/book')
|
|
184
|
-
book.get('/', (c) => c.text('List Books')) // GET /book
|
|
185
|
-
book.get('/:id', (c) => {
|
|
186
|
-
// GET /book/:id
|
|
187
|
-
const id = c.req.param('id')
|
|
188
|
-
return c.text('Get Book: ' + id)
|
|
189
|
-
})
|
|
190
|
-
book.post('/', (c) => c.text('Create Book')) // POST /book
|
|
191
|
-
```
|
|
192
|
-
|
|
193
203
|
### no strict
|
|
194
204
|
|
|
195
205
|
If `strict` is set false, `/hello`and`/hello/` are treated the same.
|
|
196
206
|
|
|
197
|
-
```
|
|
207
|
+
```ts
|
|
198
208
|
const app = new Hono({ strict: false }) // Default is true
|
|
199
209
|
|
|
200
210
|
app.get('/hello', (c) => c.text('/hello or /hello/'))
|
|
@@ -209,13 +219,38 @@ app.get('/fetch-url', async (c) => {
|
|
|
209
219
|
})
|
|
210
220
|
```
|
|
211
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
|
+
|
|
212
240
|
## Middleware
|
|
213
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
|
+
|
|
214
249
|
### Built-in Middleware
|
|
215
250
|
|
|
216
251
|
Hono has built-in middleware.
|
|
217
252
|
|
|
218
|
-
```
|
|
253
|
+
```ts
|
|
219
254
|
import { Hono } from 'hono'
|
|
220
255
|
import { poweredBy } from 'hono/powered-by'
|
|
221
256
|
import { logger } from 'hono/logger'
|
|
@@ -225,8 +260,6 @@ const app = new Hono()
|
|
|
225
260
|
|
|
226
261
|
app.use('*', poweredBy())
|
|
227
262
|
app.use('*', logger())
|
|
228
|
-
// Or you can write:
|
|
229
|
-
// app.use('*', poweredBy()).use(logger())
|
|
230
263
|
|
|
231
264
|
app.use(
|
|
232
265
|
'/auth/*',
|
|
@@ -243,7 +276,7 @@ Available built-in middleware is listed on [src/middleware](https://github.com/h
|
|
|
243
276
|
|
|
244
277
|
You can write your own middleware.
|
|
245
278
|
|
|
246
|
-
```
|
|
279
|
+
```ts
|
|
247
280
|
// Custom logger
|
|
248
281
|
app.use('*', async (c, next) => {
|
|
249
282
|
console.log(`[${c.req.method}] ${c.req.url}`)
|
|
@@ -282,11 +315,11 @@ app.onError((err, c) => {
|
|
|
282
315
|
|
|
283
316
|
## Context
|
|
284
317
|
|
|
285
|
-
To handle Request and
|
|
318
|
+
To handle Request and Response, you can use `Context` object.
|
|
286
319
|
|
|
287
320
|
### c.req
|
|
288
321
|
|
|
289
|
-
```
|
|
322
|
+
```ts
|
|
290
323
|
// Get Request object
|
|
291
324
|
app.get('/hello', (c) => {
|
|
292
325
|
const userAgent = c.req.headers.get('User-Agent')
|
|
@@ -314,13 +347,15 @@ app.get('/entry/:id', (c) => {
|
|
|
314
347
|
|
|
315
348
|
### Shortcuts for Response
|
|
316
349
|
|
|
317
|
-
```
|
|
350
|
+
```ts
|
|
318
351
|
app.get('/welcome', (c) => {
|
|
319
352
|
// Set headers
|
|
320
353
|
c.header('X-Message', 'Hello!')
|
|
321
354
|
c.header('Content-Type', 'text/plain')
|
|
355
|
+
|
|
322
356
|
// Set HTTP status code
|
|
323
357
|
c.status(201)
|
|
358
|
+
|
|
324
359
|
// Return the response body
|
|
325
360
|
return c.body('Thank you for comming')
|
|
326
361
|
})
|
|
@@ -328,14 +363,13 @@ app.get('/welcome', (c) => {
|
|
|
328
363
|
|
|
329
364
|
The Response is the same as below.
|
|
330
365
|
|
|
331
|
-
```
|
|
366
|
+
```ts
|
|
332
367
|
new Response('Thank you for comming', {
|
|
333
368
|
status: 201,
|
|
334
369
|
statusText: 'Created',
|
|
335
370
|
headers: {
|
|
336
371
|
'X-Message': 'Hello',
|
|
337
372
|
'Content-Type': 'text/plain',
|
|
338
|
-
'Content-Length': '22',
|
|
339
373
|
},
|
|
340
374
|
})
|
|
341
375
|
```
|
|
@@ -344,7 +378,7 @@ new Response('Thank you for comming', {
|
|
|
344
378
|
|
|
345
379
|
Render text as `Content-Type:text/plain`.
|
|
346
380
|
|
|
347
|
-
```
|
|
381
|
+
```ts
|
|
348
382
|
app.get('/say', (c) => {
|
|
349
383
|
return c.text('Hello!')
|
|
350
384
|
})
|
|
@@ -354,7 +388,7 @@ app.get('/say', (c) => {
|
|
|
354
388
|
|
|
355
389
|
Render JSON as `Content-Type:application/json`.
|
|
356
390
|
|
|
357
|
-
```
|
|
391
|
+
```ts
|
|
358
392
|
app.get('/api', (c) => {
|
|
359
393
|
return c.json({ message: 'Hello!' })
|
|
360
394
|
})
|
|
@@ -364,7 +398,7 @@ app.get('/api', (c) => {
|
|
|
364
398
|
|
|
365
399
|
Render HTML as `Content-Type:text/html`.
|
|
366
400
|
|
|
367
|
-
```
|
|
401
|
+
```ts
|
|
368
402
|
app.get('/', (c) => {
|
|
369
403
|
return c.html('<h1>Hello! Hono!</h1>')
|
|
370
404
|
})
|
|
@@ -374,7 +408,7 @@ app.get('/', (c) => {
|
|
|
374
408
|
|
|
375
409
|
Return the `Not Found` Response.
|
|
376
410
|
|
|
377
|
-
```
|
|
411
|
+
```ts
|
|
378
412
|
app.get('/notfound', (c) => {
|
|
379
413
|
return c.notFound()
|
|
380
414
|
})
|
|
@@ -384,14 +418,14 @@ app.get('/notfound', (c) => {
|
|
|
384
418
|
|
|
385
419
|
Redirect, default status code is `302`.
|
|
386
420
|
|
|
387
|
-
```
|
|
421
|
+
```ts
|
|
388
422
|
app.get('/redirect', (c) => c.redirect('/'))
|
|
389
423
|
app.get('/redirect-permanently', (c) => c.redirect('/', 301))
|
|
390
424
|
```
|
|
391
425
|
|
|
392
426
|
### c.res
|
|
393
427
|
|
|
394
|
-
```
|
|
428
|
+
```ts
|
|
395
429
|
// Response object
|
|
396
430
|
app.use('/', (c, next) => {
|
|
397
431
|
next()
|
|
@@ -401,7 +435,7 @@ app.use('/', (c, next) => {
|
|
|
401
435
|
|
|
402
436
|
### c.event
|
|
403
437
|
|
|
404
|
-
```
|
|
438
|
+
```ts
|
|
405
439
|
// FetchEvent object
|
|
406
440
|
app.use('*', async (c, next) => {
|
|
407
441
|
c.event.waitUntil(
|
|
@@ -413,7 +447,7 @@ app.use('*', async (c, next) => {
|
|
|
413
447
|
|
|
414
448
|
### c.env
|
|
415
449
|
|
|
416
|
-
```
|
|
450
|
+
```ts
|
|
417
451
|
// Environment object for Cloudflare Workers
|
|
418
452
|
app.get('*', async c => {
|
|
419
453
|
const counter = c.env.COUNTER
|
|
@@ -425,7 +459,7 @@ app.get('*', async c => {
|
|
|
425
459
|
|
|
426
460
|
`app.fire()` do this.
|
|
427
461
|
|
|
428
|
-
```
|
|
462
|
+
```ts
|
|
429
463
|
addEventListener('fetch', (event) => {
|
|
430
464
|
event.respondWith(this.handleEvent(event))
|
|
431
465
|
})
|
|
@@ -435,17 +469,18 @@ addEventListener('fetch', (event) => {
|
|
|
435
469
|
|
|
436
470
|
`app.fetch` for Cloudflare Module Worker syntax.
|
|
437
471
|
|
|
438
|
-
```
|
|
472
|
+
```ts
|
|
439
473
|
export default {
|
|
440
474
|
fetch(request: Request, env: Env, event: FetchEvent) {
|
|
441
475
|
return app.fetch(request, env, event)
|
|
442
476
|
},
|
|
443
477
|
}
|
|
478
|
+
```
|
|
444
479
|
|
|
445
|
-
/*
|
|
446
480
|
or just do:
|
|
481
|
+
|
|
482
|
+
```ts
|
|
447
483
|
export default app
|
|
448
|
-
*/
|
|
449
484
|
```
|
|
450
485
|
|
|
451
486
|
## request
|
|
@@ -461,61 +496,35 @@ test('GET /hello is ok', async () => {
|
|
|
461
496
|
|
|
462
497
|
## Cloudflare Workers with Hono
|
|
463
498
|
|
|
464
|
-
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.
|
|
465
500
|
|
|
466
501
|
Let's write your first code for Cloudflare Workers with Hono.
|
|
467
502
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
### Caution
|
|
471
|
-
|
|
472
|
-
**Wrangler 1.x** does not support importing middleware. We recommend two ways:
|
|
473
|
-
|
|
474
|
-
1. Use [Wragler 2.0 Beta](https://github.com/cloudflare/wrangler2).
|
|
475
|
-
2. Build without webpack 4.x. For example, you can use esbuild. See [the starter template](https://github.com/honojs/hono-minimal).
|
|
476
|
-
|
|
477
|
-
---
|
|
478
|
-
|
|
479
|
-
### 1. `npm init`
|
|
480
|
-
|
|
481
|
-
Make a npm skeleton directory.
|
|
482
|
-
|
|
483
|
-
```sh
|
|
484
|
-
mkdir hono-example
|
|
485
|
-
cd hono-example
|
|
486
|
-
npm init -y
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
### 2. `wrangler init`
|
|
503
|
+
### 1. `wrangler init`
|
|
490
504
|
|
|
491
505
|
Initialize as a wrangler project.
|
|
492
506
|
|
|
493
|
-
```sh
|
|
494
|
-
npx wrangler@beta init
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
Answer the questions. If you want, you can answer `y`.
|
|
498
|
-
|
|
499
507
|
```
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
508
|
+
mkdir hono-example
|
|
509
|
+
cd hono-example
|
|
510
|
+
npx wrangler init -y
|
|
503
511
|
```
|
|
504
512
|
|
|
505
|
-
###
|
|
513
|
+
### 2. `npm install hono`
|
|
506
514
|
|
|
507
515
|
Install `hono` from the npm registry.
|
|
508
516
|
|
|
509
|
-
```
|
|
517
|
+
```
|
|
518
|
+
npm init -y
|
|
510
519
|
npm i hono
|
|
511
520
|
```
|
|
512
521
|
|
|
513
|
-
###
|
|
522
|
+
### 3. Write your app
|
|
514
523
|
|
|
515
|
-
Only 4 lines!!
|
|
524
|
+
Edit `src/index.ts`. Only 4 lines!!
|
|
516
525
|
|
|
517
|
-
```
|
|
518
|
-
// index.
|
|
526
|
+
```ts
|
|
527
|
+
// src/index.ts
|
|
519
528
|
import { Hono } from 'hono'
|
|
520
529
|
const app = new Hono()
|
|
521
530
|
|
|
@@ -524,20 +533,20 @@ app.get('/', (c) => c.text('Hello! Hono!'))
|
|
|
524
533
|
app.fire()
|
|
525
534
|
```
|
|
526
535
|
|
|
527
|
-
###
|
|
536
|
+
### 4. Run
|
|
528
537
|
|
|
529
538
|
Run the development server locally. Then, access `http://127.0.0.1:8787/` in your Web browser.
|
|
530
539
|
|
|
531
|
-
```
|
|
532
|
-
npx wrangler
|
|
540
|
+
```
|
|
541
|
+
npx wrangler dev
|
|
533
542
|
```
|
|
534
543
|
|
|
535
|
-
###
|
|
544
|
+
### 5. Publish
|
|
536
545
|
|
|
537
546
|
Deploy to Cloudflare. That's all!
|
|
538
547
|
|
|
539
|
-
```
|
|
540
|
-
npx wrangler
|
|
548
|
+
```
|
|
549
|
+
npx wrangler publish ./src/index.ts
|
|
541
550
|
```
|
|
542
551
|
|
|
543
552
|
## Starter template
|
|
@@ -546,8 +555,8 @@ You can start making your Cloudflare Workers application with [the starter templ
|
|
|
546
555
|
|
|
547
556
|
To generate a project skelton, run this command.
|
|
548
557
|
|
|
549
|
-
```
|
|
550
|
-
|
|
558
|
+
```
|
|
559
|
+
npx create-cloudflare my-app https://github.com/honojs/hono-minimal
|
|
551
560
|
```
|
|
552
561
|
|
|
553
562
|
## Examples
|
|
@@ -578,7 +587,7 @@ Contributions Welcome! You can contribute in the following ways.
|
|
|
578
587
|
|
|
579
588
|
## Contributors
|
|
580
589
|
|
|
581
|
-
Thanks to [all contributors](https://github.com/honojs/hono/graphs/contributors)!
|
|
590
|
+
Thanks to [all contributors](https://github.com/honojs/hono/graphs/contributors)! Especially, [@metrue](https://github.com/metrue) and [@usualoma](https://github.com/usualoma)!
|
|
582
591
|
|
|
583
592
|
## Author
|
|
584
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 {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|