Skip to content

Commit

Permalink
docs: add examples (#539)
Browse files Browse the repository at this point in the history
Co-authored-by: Pooya Parsa <pooya@pi0.io>
  • Loading branch information
Barbapapazes and pi0 authored Dec 7, 2023
1 parent 39f9434 commit 53703dc
Show file tree
Hide file tree
Showing 19 changed files with 441 additions and 8 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

H3 (pronounced as /eɪtʃθriː/, like h-3) is a minimal h(ttp) framework built for high performance and portability.

👉 [Online Playground](https://stackblitz.com/github/unjs/h3/tree/main/playground?startScript=dev)
👉 [Online Playground](https://stackblitz.com/github/unjs/h3/tree/main/playground)

👉 [Online Examples Playground](https://stackblitz.com/github/unjs/h3/tree/main/examples)

## Features

Expand Down Expand Up @@ -135,7 +137,7 @@ app.use(router);

Routes are internally stored in a [Radix Tree](https://en.wikipedia.org/wiki/Radix_tree) and matched using [unjs/radix3](https://github.com/unjs/radix3).

For using nested routers, see [this example](https://stackblitz.com/edit/github-2bmusk?file=app.ts&startScript=dev)
For using nested routers, see [this example](./examples/nested-router.ts)

## More app usage examples

Expand Down
23 changes: 23 additions & 0 deletions examples/body.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createApp, createRouter, defineEventHandler, readBody } from "h3";

export const app = createApp();

const router = createRouter()
.get(
"/",
defineEventHandler(() => {
return "use POST method to try!";
}),
)
.post(
"/",
defineEventHandler(async (event) => {
const body = await readBody(event);
// Use can also use `readFormData` to get a FormData object, `readMultiPartFormData` to get an array of MultiPartData or `readRawBody` to get a Buffer.
return {
body,
};
}),
);

app.use(router);
31 changes: 31 additions & 0 deletions examples/cookies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
createApp,
createRouter,
defineEventHandler,
getCookie,
setCookie,
} from "h3";

export const app = createApp();

const router = createRouter()
.get(
"/",
defineEventHandler((event) => {
const testCookie = getCookie(event, "testCookie");
return `testCookie is ${JSON.stringify(
testCookie,
)} (go to /set to set it)`;
}),
)
.get(
"/set",
defineEventHandler((event) => {
// By default, path is set to `/`. You can use any of the options supported by the Set-Cookie header.
// @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
setCookie(event, "testCookie", "bar", { httpOnly: true });
return "testCookie is set";
}),
);

app.use(router);
37 changes: 37 additions & 0 deletions examples/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createApp, createError, createRouter, defineEventHandler } from "h3";

export const app = createApp({ debug: true });

const router = createRouter()
.get(
"/",
defineEventHandler(() => {
// Always "throw" errors to propgate them to the error handler
throw createError({ statusMessage: "Simple error!", statusCode: 301 });
}),
)
.get(
"/complexe-error",
defineEventHandler(() => {
// You can fully customize errors by adding data, cause and if it's a fatal error or not
throw createError({
status: 400,
message: "Bad request",
statusMessage: "Bad request message",
});
}),
)
.get(
"/fatal-error",
defineEventHandler(() => {
// Fatal errors will stop the execution of the current request and will be logged
throw createError({
status: 500,
message: "Fatal error",
fatal: true,
data: { foo: "bar" },
});
}),
);

app.use(router);
48 changes: 48 additions & 0 deletions examples/first-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { createApp, defineEventHandler, toNodeListener } from "h3";

Check warning on line 1 in examples/first-server.ts

View workflow job for this annotation

GitHub Actions / autofix

'toNodeListener' is defined but never used

Check warning on line 1 in examples/first-server.ts

View workflow job for this annotation

GitHub Actions / ci (16)

'toNodeListener' is defined but never used

Check warning on line 1 in examples/first-server.ts

View workflow job for this annotation

GitHub Actions / ci (18)

'toNodeListener' is defined but never used

Check warning on line 1 in examples/first-server.ts

View workflow job for this annotation

GitHub Actions / ci (20)

'toNodeListener' is defined but never used

export const app = createApp();

app
// `/` is the root path and will response to every request.
.use(
"/first-request",
defineEventHandler(() => {
return "hello world";
}),
)
.use(
"/hello",
defineEventHandler(() => {
return "world";
}),
)
.use(
"/json",
defineEventHandler(() => {
// Automatically set the `Content-Type` header to `application/json`.
return {
hello: "world",
};
}),
)
.use(
"/html",
defineEventHandler(() => {
// By default, the `Content-Type` header is set to `text/html`.
return "<h1>hello world</h1>";
}),
)
.use(
"/buffer",
defineEventHandler(() => {
// No `Content-Type` header is set by default. You can set it manually using `setHeader`.
return Buffer.from("hello world");
}),
)
.use(
"/blob",
defineEventHandler(() => {
// No `Content-Type` header is set by default. You can set it manually using `setHeader`.
return new Blob(["hello world"]);
}),
);
30 changes: 30 additions & 0 deletions examples/handler-middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
createApp,
createRouter,
defineEventHandler,
defineRequestMiddleware,
defineResponseMiddleware,
} from "h3";

export const app = createApp();

const router = createRouter().get(
"/",
defineEventHandler({
onRequest: defineRequestMiddleware(() => {
// Do anything you want here like authentication, rate limiting, etc.
console.log("onRequest");
// Never return anything from onRequest to avoid to close the connection
}),
onBeforeResponse: defineResponseMiddleware(() => {
// Do anything you want here like logging, collecting metrics, or output compression, etc.
console.log("onResponse");
// Never return anything from onResponse to avoid to close the connection
}),
handler: defineEventHandler(() => {
return "GET: hello world";
}),
}),
);

app.use(router);
35 changes: 35 additions & 0 deletions examples/headers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
createApp,
createRouter,
defineEventHandler,
getRequestHeader,
getResponseHeaders,
setResponseHeader,
} from "h3";

export const app = createApp();

const router = createRouter().get(
"/user-agent",
defineEventHandler((event) => {
const userAgent = getRequestHeader(event, "user-agent");
// You can also use `getRequestHeaders` to get all headers at once.
// const headers = getRequestHeaders(event)

setResponseHeader(event, "content-type", "text/plain");
setResponseHeader(event, "x-server", "nitro");
// You can also use `setResponseHeaders` to set multiple headers at once.
// setResponseHeaders(event, { 'x-server': 'nitro', 'content-type': 'text/plain' })

const responseHeaders = getResponseHeaders(event);
// You can also use `getResponseHeader` to get a single header.
// const contentType = getResponseHeader(event, 'content-type')

return {
userAgent,
responseHeaders,
};
}),
);

app.use(router);
19 changes: 19 additions & 0 deletions examples/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { readdir } from "node:fs/promises";
import { listenAndWatch } from "listhen";

async function promptExample() {
const { consola } = await import("consola");
const exampleFiles = await readdir(new URL(".", import.meta.url)).then((r) =>
r.filter((f) => f.endsWith(".ts")),
);
return await consola.prompt("Select an example to run:", {
type: "select",
options: exampleFiles,
});
}

const exampleFile = process.argv[2] || (await promptExample());

listenAndWatch(new URL(exampleFile, import.meta.url), {
name: `H3 example: ${exampleFile}`,
});
27 changes: 27 additions & 0 deletions examples/nested-router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
createApp,
defineEventHandler,
toNodeListener,

Check warning on line 4 in examples/nested-router.ts

View workflow job for this annotation

GitHub Actions / autofix

'toNodeListener' is defined but never used

Check warning on line 4 in examples/nested-router.ts

View workflow job for this annotation

GitHub Actions / ci (16)

'toNodeListener' is defined but never used

Check warning on line 4 in examples/nested-router.ts

View workflow job for this annotation

GitHub Actions / ci (18)

'toNodeListener' is defined but never used

Check warning on line 4 in examples/nested-router.ts

View workflow job for this annotation

GitHub Actions / ci (20)

'toNodeListener' is defined but never used
createRouter,
useBase,
sendRedirect,
} from "h3";

// Init App
export const app = createApp({ debug: true });

// Main Router
const router = createRouter();
router.use(
"/",
defineEventHandler((event) => sendRedirect(event, "/api/test")),
);
app.use(router);

// Nested API Ruter
const apiRouter = createRouter();
router.use("/api/**", useBase("/api", apiRouter.handler));
apiRouter.use(
"/test",
defineEventHandler(() => "API /test"),
);
12 changes: 12 additions & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "h3-examples",
"private": true,
"scripts": {
"dev": "node ./index.mjs"
},
"dependencies": {
"h3": "latest",
"listhen": "latest",
"consola": "latest"
}
}
18 changes: 18 additions & 0 deletions examples/query-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createApp, createRouter, defineEventHandler, getQuery } from "h3";

export const app = createApp();

const router = createRouter().get(
"/",
defineEventHandler((event) => {
const query = getQuery(event);

if (!query.name) {
return "Set ?name=yourname in URL to get a greeting!";
}

return `Hello ${query.name}`;
}),
);

app.use(router);
20 changes: 20 additions & 0 deletions examples/redirect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createApp, createRouter, defineEventHandler, sendRedirect } from "h3";

export const app = createApp();

const router = createRouter()
.get(
"/unjs",
defineEventHandler((event) => {
return sendRedirect(event, "https://unjs.io/packages/h3"); // 302 Found by default
}),
)
.get(
"/permanent",
defineEventHandler((event) => {
// You can use any 3xx status code you want
return sendRedirect(event, "https://unjs.io/packages/h3", 301);
}),
);

app.use(router);
43 changes: 43 additions & 0 deletions examples/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createApp, createRouter, defineEventHandler } from "h3";

export const app = createApp();

const router = createRouter()
.get(
"/",
defineEventHandler(() => {
return "GET: hello world";
}),
)
.post(
"/",
defineEventHandler(() => {
return "POST: hello world";
}),
)
.put(
"/",
defineEventHandler(() => {
return "PUT: hello world";
}),
)
.delete(
"/",
defineEventHandler(() => {
return "DELETE: hello world";
}),
)
.patch(
"/",
defineEventHandler(() => {
return "PATCH: hello world";
}),
)
.head(
"/",
defineEventHandler(() => {
return "HEAD: hello world";
}),
);

app.use(router);
Loading

0 comments on commit 53703dc

Please sign in to comment.