UNPKG

6.13 kBMarkdownView Raw
1[![npm downloads](https://img.shields.io/npm/dm/h3.svg?style=flat-square)](https://npmjs.com/package/h3)
2[![version](https://img.shields.io/npm/v/h3/latest.svg?style=flat-square)](https://npmjs.com/package/h3)
3[![bundlephobia](https://img.shields.io/bundlephobia/min/h3/latest.svg?style=flat-square)](https://bundlephobia.com/result?p=h3)
4[![build status](https://img.shields.io/github/workflow/status/unjs/h3/ci/main?style=flat-square)](https://github.com/unjs/h3/actions)
5[![coverage](https://img.shields.io/codecov/c/gh/unjs/h3/main?style=flat-square)](https://codecov.io/gh/unjs/h3)
6[![jsDocs.io](https://img.shields.io/badge/jsDocs.io-reference-blue?style=flat-square)](https://www.jsdocs.io/package/h3)
7
8> H3 is a minimal h(ttp) framework built for high performance and portability
9
10<!-- ![h3 - Tiny JavaScript Server](.github/banner.svg) -->
11
12## Features
13
14✔️ &nbsp;**Portable:** Works perfectly in Serverless, Workers, and Node.js
15
16✔️ &nbsp;**Compatible:** Support connect/express middleware
17
18✔️ &nbsp;**Minimal:** Small, tree-shakable and zero-dependency
19
20✔️ &nbsp;**Modern:** Native promise support
21
22✔️ &nbsp;**Extendable:** Ships with a set of composable utilities but can be extended
23
24✔️ &nbsp;**Router:** Super fast route matching using [unjs/radix3](https://github.com/unjs/radix3)
25
26## Install
27
28```bash
29# Using npm
30npm install h3
31
32# Using yarn
33yarn add h3
34
35# Using pnpm
36pnpm add h3
37```
38
39## Usage
40
41```ts
42import { createServer } from 'http'
43import { createApp } from 'h3'
44
45const app = createApp()
46app.use('/', () => 'Hello world!')
47
48createServer(app).listen(process.env.PORT || 3000)
49```
50
51<details>
52 <summary>Example using <a href="https://github.com/unjs/listhen">listhen</a> for an elegant listener.</summary>
53
54```ts
55import { createApp } from 'h3'
56import { listen } from 'listhen'
57
58const app = createApp()
59app.use('/', () => 'Hello world!')
60
61listen(app)
62```
63</details>
64
65## Router
66
67The `app` instance created by `h3` uses a middleware stack (see [how it works](#how-it-works)) with the ability to match route prefix and apply matched middleware.
68
69To opt-in using a more advanced and convenient routing system, we can create a router instance and register it to app instance.
70
71```ts
72import { createApp, createRouter } from 'h3'
73
74const app = createApp()
75
76const router = createRouter()
77 .get('/', () => 'Hello World!')
78 .get('/hello/:name', req => `Hello ${req.context.params.name}!`)
79
80app.use(router)
81```
82
83**Tip:** We can register same route more than once with different methods.
84
85Routes are internally stored in a [Radix Tree](https://en.wikipedia.org/wiki/Radix_tree) and matched using [unjs/radix3](https://github.com/unjs/radix3).
86
87## More usage examples
88
89```js
90// Handle can directly return object or Promise<object> for JSON response
91app.use('/api', (req) => ({ url: req.url }))
92
93// We can have better matching other than quick prefix match
94app.use('/odd', () => 'Is odd!', { match: url => url.substr(1) % 2 })
95
96// Handle can directly return string for HTML response
97app.use(() => '<h1>Hello world!</h1>')
98
99// We can chain calls to .use()
100app.use('/1', () => '<h1>Hello world!</h1>')
101 .use('/2', () => '<h1>Goodbye!</h1>')
102
103// Legacy middleware with 3rd argument are automatically promisified
104app.use((req, res, next) => { req.setHeader('X-Foo', 'bar'); next() })
105
106// Force promisify a legacy middleware
107// app.use(someMiddleware, { promisify: true })
108
109// Lazy loaded routes using { lazy: true }
110// app.use('/big', () => import('./big'), { lazy: true })
111```
112
113## Utilities
114
115### Built-in
116
117Instead of adding helpers to `req` and `res`, h3 exposes them as composable utilities.
118
119- `useRawBody(req, encoding?)`
120- `useBody(req)`
121- `useCookies(req)`
122- `useCookie(req, name)`
123- `setCookie(res, name, value, opts?)`
124- `deleteCookie(res, name, opts?)`
125- `useQuery(req)`
126- `getRouterParams(event)`
127- `send(res, data, type?)`
128- `sendRedirect(res, location, code=302)`
129- `getRequestHeaders(event, headers)` (alias: `getHeaders`)
130- `getRequestHeader(event, name)` (alias: `getHeader`)
131- `setResponseHeaders(event, headers)` (alias: `setHeaders`)
132- `setResponseHeader(event, name, value)` (alias: `setHeader`)
133- `appendResponseHeaders(event, headers)` (alias: `appendHeaders`)
134- `appendResponseHeader(event, name, value)` (alias: `appendHeader`)
135- `createError({ statusCode, statusMessage, data? })`
136- `sendError(res, error, debug?)`
137- `defineHandle(handle)`
138- `defineMiddleware(middlware)`
139- `useMethod(req, default?)`
140- `isMethod(req, expected, allowHead?)`
141- `assertMethod(req, expected, allowHead?)`
142
143👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).
144
145### Add-ons
146
147More composable utilities can be found in community packages.
148
149- `validateBody(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
150- `validateQuery(event, schema)` from [h3-typebox](https://github.com/kevinmarrec/h3-typebox)
151
152## How it works?
153
154Using `createApp`, it returns a standard `(req, res)` handler function and internally an array called middleware stack. using`use()` method we can add an item to this internal stack.
155
156When a request comes, each stack item that matches the route will be called and resolved until [`res.writableEnded`](https://nodejs.org/api/http.html#http_response_writableended) flag is set, which means the response is sent. If `writableEnded` is not set after all middleware, a `404` error will be thrown. And if one of the stack items resolves to a value, it will be serialized and sent as response as a shorthand method to sending responses.
157
158For maximum compatibility with connect/express middleware (`req, res, next?` signature), h3 converts classic middleware into a promisified version ready to use with stack runner:
159
160- If middleware has 3rd next/callback param, the promise will `resolve/reject` when called
161- If middleware returns a promise, it will be **chained** to the main promise
162- If calling middleware throws an immediate error, the promise will be rejected
163- On `close` and `error` events of res, the promise will `resolve/reject` (to ensure if middleware simply calls `res.end`)
164
165## License
166
167MIT