h3
repository·main·Indexed 26 days ago
https://github.com/h3js/h3A minimal, high-performance, and portable HTTP framework designed for building web services and APIs. It supports multiple runtimes including Node.js, Deno, Bun, and Cloudflare Workers, featuring a four-stage request lifecycle, flexible routing with dynamic and wildcard parameters, and a comprehensive middleware system including global and route-specific handlers.
What's inside h3
- H3 (pronounced /eɪtʃθriː/) is a minimal HTTP framework designed for high performance and portability. It is a lightweight solution for building web servers and APIs.
Understand the H3Event object
mainIn H3, every HTTP request creates an
H3Eventobject. This object is passed through all lifecycle hooks and event handlers, acting as the central container for the incoming request, the prepared response, and the request context.app.get("/", async (event) => { // Log HTTP request console.log(`[${event.req.method}] ${event.req.url}`); // Parsed URL and query params const searchParams = event.url.searchParams; // Try to read request JSON body const jsonBody = await event.req.json().catch(() => {}); return "OK"; });Explore H3 Utility Categories
mainH3 is a composable framework that provides a lightweight core. Instead of a monolithic API, functionality is provided through specialized utility groups. You can use built-in utilities or create your own for the following categories:
- Request: Utilities for handling incoming requests.
- Response: Utilities for preparing and sending responses.
- Cookie: Utilities for managing cookies.
- Security: Utilities for security-related tasks.
- Proxy: Utilities for proxying requests.
- MCP: Model Context Protocol related utilities.
- More: Additional miscellaneous utilities.
- Community: Utilities provided by the community.
Quick Start with H3
mainTo create a basic web server, instantiate a new
H3class, define routes using HTTP method helpers (like.get()), and use theservefunction to start the listener on a specific port.import { H3, serve } from "h3"; const app = new H3().get("/", (event) => "⚡️ Tadaa!"); serve(app, { port: 3000 });Stream responses to the client
mainYou can stream data to a client as soon as it becomes available, which is ideal for large files or long-running responses. To implement this in H3, create a
ReadableStreamusing the standard Web API and return it from your event handler.When streaming, it is recommended to set the following response headers manually via
event.res.headers:Content-Type: To specify the data format (e.g.,text/html).Cache-Control: Set tono-cacheto prevent caching of the stream.Transfer-Encoding: Set tochunkedto indicate chunked transfer encoding.
import { H3 } from "h3"; export const app = new H3(); app.use((event) => { // Set response headers for streaming event.res.headers.set("Content-Type", "text/html"); event.res.headers.set("Cache-Control", "no-cache"); event.res.headers.set("Transfer-Encoding", "chunked"); const stream = new ReadableStream({ start(controller) { controller.enqueue("<ul>"); const interval = setInterval(() => { controller.enqueue("<li>" + Math.random() + "</li>"); }, 100); setTimeout(() => { clearInterval(interval); controller.enqueue("</ul>"); controller.close(); }, 1000); }, cancel() { // Handle cleanup if the stream is cancelled }, }); return stream; });Mount nested H3 apps
mainYou can use the
.mount(prefix, subApp)method to add a nested H3 instance to a main H3 instance. When an H3 sub-app is mounted, its routes and middleware are merged with the provided base URL prefix.Important considerations:
- Path Resolution: In a wildcard route like
/**:slugwithin a mounted app, thepathnamewill include the full path (including the prefix), but the wildcard parameter will only capture the part after the prefix. - Inheritance: Global configuration and hooks are not inherited from the nested app. You should define global config and hooks on the main app instance.
import { H3, serve } from "h3"; const nestedApp = new H3() .use((event) => { event.res.headers.set("x-api", "1"); }) .get("/**:slug", (event) => ({ pathname: event.url.pathname, slug: event.context.params?.slug, })); const app = new H3().mount("/api", nestedApp);- Path Resolution: In a wildcard route like
Define dynamic and wildcard routes
mainH3 supports dynamic parameters and wildcard matching for flexible routing:
- Dynamic Parameters: Use the
:prefix to define named parameters. Access them viaevent.context.params. - Optional Unnamed Parameters: Use
*for unnamed optional parameters. - Wildcard Routes: Use the
**prefix to match multiple levels of sub-routes. The full wildcard content is stored inevent.context.params._as a single string.
Syntax Example Matches Description :name/hello/:name/hello/BobNamed parameter */hello/*/hello/anythingUnnamed optional parameter **/hello/**/hello/foo/barMulti-level wildcard - Dynamic Parameters: Use the
Send errors by throwing `HTTPError`
mainTo send specific HTTP error responses, throw an instance of
HTTPError. H3 supports several ways to instantiate it:- Message and Status: Provide a message string and a status code object.
- Static Method: Use
HTTPError.status(code, statusText). - Configuration Object: Pass a single object containing all error details.
When an
HTTPErroris thrown, H3 returns a JSON response containing the status, statusText, message, and any additionaldataorbodyproperties provided.import { HTTPError } from "h3"; app.get("/error", (event) => { // Using message and details throw new HTTPError("Invalid user input", { status: 400 }); // Using HTTPError.status(code) throw HTTPError.status(400, "Bad Request"); // Using single object throw new HTTPError({ status: 400, statusText: "Bad Request", message: "Invalid user input", data: { field: "email" }, body: { date: new Date().toJSON() }, headers: {}, }); });Configure Node.js runtime for H3 v2
mainInstall H3
mainInstallh3as a dependency in your project using your preferred package manager.Run an H3 server
mainAfter creating your server entry file (e.g.,
server.mjs), run it using your preferred runtime:Node.js
node --watch ./server.mjsDeno
deno run -A --watch ./server.mjsBun
bun run --watch server.mjsHandle responses in H3 v2
mainIn H3 v2, you should always explicitly return the response body or throw an error. Replace legacysendutilities withreturnstatements. H3 automatically detects and handles text, JSON, streams, or webResponseobjects.