Skip to content

Commit 142fe0c

Browse files
committed
update
1 parent 5fb63b3 commit 142fe0c

File tree

12 files changed

+209
-56
lines changed

12 files changed

+209
-56
lines changed

docs/content/2.concepts/1.app.md

Lines changed: 104 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,123 @@
11
---
22
title: H3 App
3-
description:
3+
description: Learn more about H3 app usage
44
---
55

6+
Every H3 server has at least one app instance. It is the beating hearth of your server.
7+
8+
## Initialing H3 App
9+
10+
You can create a new h3 app instance using `createApp` utility:
11+
12+
```js [app.mjs]
13+
import { createApp } from "h3";
14+
15+
const app = createApp();
16+
```
17+
18+
You can also pass global app configurtions when initializing an app:
19+
20+
```js
21+
const app = createApp({
22+
debug: true,
23+
});
24+
```
25+
26+
## Adding Event Handlers
27+
28+
After initializing app instance, we need to register [Event Handlers](/concepts/event-handler) to our app to handle the logic.
29+
30+
In order to register event handlers, we have to use `app.use()` method. Each handler can be registred without prefix (middleware) or with a static route prefix.
31+
32+
When an HTTP request comes, H3, tries to call our registred handlers (that match the prefix) one by one (**in order that we add them**) until one of them ends the request. This is called "stack runner".
33+
34+
**Example:** Resgister a simple `/hello` route:
35+
636
```js
7-
// Handle can directly return object or Promise<object> for JSON response
837
app.use(
9-
"/api",
10-
eventHandler((event) => ({ url: event.node.req.url })),
38+
"/hello",
39+
eventHandler(() => "Hello World"),
1140
);
41+
```
42+
43+
**Note:** Above example matches any request starting with `/hello`, including `/hello` but also `/hello/world` and `/hello/you`.
44+
45+
If event handlers don't register a prefix, they will match every request.
46+
47+
**Example:** Simple request logger
1248

13-
// We can have better matching other than quick prefix match
49+
```js
1450
app.use(
15-
"/odd",
16-
eventHandler(() => "Is odd!"),
17-
{ match: (url) => url.substr(1) % 2 },
51+
eventHandler((event) => {
52+
console.log("Request:", event.path);
53+
// Since we don't return anything, h3, goes to the next middleware
54+
}),
1855
);
1956

20-
// Handle can directly return string for HTML response
21-
app.use(eventHandler(() => "<h1>Hello world!</h1>"));
22-
23-
// We can chain calls to .use()
24-
app
25-
.use(
26-
"/1",
27-
eventHandler(() => "<h1>Hello world!</h1>"),
28-
)
29-
.use(
30-
"/2",
31-
eventHandler(() => "<h1>Goodbye!</h1>"),
32-
);
33-
34-
// We can proxy requests and rewrite cookie's domain and path
3557
app.use(
36-
"/api",
37-
eventHandler((event) =>
38-
proxyRequest(event, "https://example.com", {
39-
// f.e. keep one domain unchanged, rewrite one domain and remove other domains
40-
cookieDomainRewrite: {
41-
"example.com": "example.com",
42-
"example.com": "somecompany.co.uk",
43-
"*": "",
44-
},
45-
cookiePathRewrite: {
46-
"/": "/api",
47-
},
48-
}),
49-
),
58+
"/hello",
59+
eventHandler(() => "Hello World"),
5060
);
61+
```
62+
63+
**Note:** Avoid adding global middleware as much as possible. They will be soon the enemy of your application performance and make scaling project size harder as global logic can become complex and tricky to manage!
64+
65+
There are couple of advanced option you can also provide when registering an event handler as last object.
5166

52-
// Legacy middleware with 3rd argument are automatically promisified
67+
### Custom Matcher
68+
69+
If you need matching logic more advanced than prefix matching but simpler than using a router, you can use custom `match` option:
70+
71+
**Example** Only match odd number routes (`/2`, `/4`, `/8`, ...)
72+
73+
```js
5374
app.use(
54-
fromNodeMiddleware((req, res, next) => {
55-
req.setHeader("x-foo", "bar");
56-
next();
57-
}),
75+
"/",
76+
eventHandler(() => "This is odd!"),
77+
{ match: (url) => url.substr(1) % 2 },
5878
);
79+
```
5980

60-
// Lazy loaded routes using { lazy: true }
81+
### Lazy Matcher
82+
83+
You can provide a callback function that h3 uses on first time matching handler to load it. It is particulary useful for dynamic imports to reduce server startup time.
84+
85+
**Example:**
86+
87+
```js
6188
app.use("/big", () => import("./big-handler"), { lazy: true });
6289
```
90+
91+
## Sending Responses
92+
93+
When a request comes, h3 app asyncly calls matching handlers and waits for them one-by-one. The first handler that sends a response by directly returning a value or using a response utility, steps h3 from running the rest of handlers.
94+
95+
If all handlers get called and there is still no response, h3 will automatically throw a 404 error.
96+
97+
The simplest way to handle response, is to directly return a value from event handlers. See [Event Handlers](/concepts/event-handler#sending-responses) for possible values.
98+
99+
## Event Handling
100+
101+
When handling a request, if one of the handlers throws an error, H3 app will automatically catch it and renders error. You can override default error handler using `onError` option.
102+
103+
<!-- TODO: Examples -->
104+
105+
## Global Hooks
106+
107+
When initializing an H3 app, you can register global hooks:
108+
109+
- `onError`
110+
- `onRequest`
111+
- `onBeforeResponse`
112+
- `onAfterResponse`
113+
114+
<!-- TODO: Examples -->
115+
116+
## App Properties (advanced)
117+
118+
H3 app instance has some additional propertier. However it is usually not recommanded to directly access them unless you know what are you doing!
119+
120+
- `app.stack`: An ordered array of currently registred event handlers.
121+
- Each item has `route` and `handler` properties.
122+
- `app.options`: Global options object provided when initializing the app
123+
- `app.handler`: Direct stack handler function (unsafe)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: Event Handlers
3+
description: Learn more about H3 event handlers
4+
---
5+
6+
Event handlers are the building blocks to define applicaion logic.
7+
8+
You can define event handlers using `defineEventHandler` or `eventHandler` helper utilities (they are aliases and both do exactly the same!).
9+
10+
```js
11+
import { defineEventHandler } from "h3";
12+
13+
const apiHandler = defineEventHandler((event) => {
14+
return "Response";
15+
});
16+
```
17+
18+
Event handlers can be registed to [App Instance](/concepts/app) or [Router Instance](/concepts/router.)
19+
20+
## Sending Responses
21+
22+
You can directly send responses by returning a value from event handlers. It can be:
23+
24+
- JSON serializable value: If returning a json object or serializable value, it will be stringified and sent with default `application/json` content-type.
25+
- `string`: Will be sent as-is using default `application/html` content-type.
26+
- `null` value: H3 with end response with `204 - No Content` status code.
27+
- [Web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) or [node `Readable`](https://nodejs.org/api/stream.html#readable-streams)
28+
- [Web `ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) or [node `Buffer`](https://nodejs.org/api/buffer.html#buffer)
29+
- [Web Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response)
30+
- [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) instance (suupported but instead `throw` errors, it is much better!!)
31+
32+
All H3 event handler support `async/await` syntax. Therefore any of above values could also be wrapped in a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
33+
34+
**Example:** Send HTML response:
35+
36+
```js
37+
app.use(eventHandler(async (event) => "<h1>Hello world!</h1>"));
38+
```
39+
40+
**Example:** Send JSON response:
41+
42+
```js
43+
// Handle can directly return object or Promise<object> for JSON response
44+
app.use(
45+
"/api",
46+
eventHandler(async (event) => ({ url: event.node.req.url })),
47+
);
48+
```

docs/content/2.concepts/2.event.md

Lines changed: 0 additions & 4 deletions
This file was deleted.

docs/content/2.concepts/3.event-handler.md

Lines changed: 0 additions & 4 deletions
This file was deleted.

docs/content/2.concepts/3.event.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: H3 Event
3+
description: Learn more about H3 event objects
4+
---
5+
6+
H3 uses a unified event object to keep track of an incoming request shared between utilities.
7+
8+
Properties:
9+
10+
- `method`
11+
- `path`
12+
- `headers`
13+
- `handled`
14+
15+
Methods:
16+
17+
- `respondWith`
18+
-
19+
20+
[[WIP]]

docs/content/2.concepts/4.router.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: Routing
33
description:
44
---
55

6-
The `app` instance created by `h3` uses a middleware stack (see [how it works](./src/app.ts)) with the ability to match route prefix and apply matched middleware.
6+
The [`app` instance](/concepts/app) created by `h3` uses a middleware stack with the ability to match route prefix and apply matched middleware.
77

88
To opt-in using a more advanced and convenient routing system, we can create a router instance and register it to app instance.
99

docs/content/2.concepts/5.composables.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ description:
44
---
55

66
H3 has a concept of composable utilities that accept `event` (from `eventHandler((event) => {})`) as their first argument. This has several performance benefits over injecting them to `event` or `app` instances in global middleware commonly used in Node.js frameworks, such as Express. This concept means only required code is evaluated and bundled, and the rest of the utilities can be tree-shaken when not used.
7+
8+
[[WIP]]

docs/content/2.concepts/6.adapters.md

Lines changed: 0 additions & 4 deletions
This file was deleted.

docs/content/4.utils/other.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,15 @@ description:
1515
#### Cache
1616

1717
- `handleCacheHeaders(event, opts)`
18+
19+
#### Legacy
20+
21+
```js
22+
// Legacy middleware with 3rd argument are automatically promisified
23+
app.use(
24+
fromNodeMiddleware((req, res, next) => {
25+
req.setHeader("x-foo", "bar");
26+
next();
27+
}),
28+
);
29+
```

docs/content/4.utils/proxy.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,22 @@ description:
77
- `proxyRequest(event, { target, ...options })`
88
- `fetchWithEvent(event, req, init, { fetch? }?)`
99
- `getProxyRequestHeaders(event)`
10+
11+
```js
12+
app.use(
13+
"/api",
14+
eventHandler((event) =>
15+
proxyRequest(event, "https://example.com", {
16+
// f.e. keep one domain unchanged, rewrite one domain and remove other domains
17+
cookieDomainRewrite: {
18+
"example.com": "example.com",
19+
"example.com": "somecompany.co.uk",
20+
"*": "",
21+
},
22+
cookiePathRewrite: {
23+
"/": "/api",
24+
},
25+
}),
26+
),
27+
);
28+
```

docs/content/99.furthor/plain-adapter.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
title: Plain Adapter
33
description:
44
---
5+
6+
[[WIP]]

playground/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ router.get(
1111
return { path: event.path, message: "Hello World!" };
1212
}),
1313
);
14+
app.use("/", () => {}, {});

0 commit comments

Comments
 (0)