h3

repository·main·Indexed 26 days ago

https://github.com/h3js/h3

A 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.

Tokens
30.4K
Snippets
100
Records
175
Agent score
90%

What's inside h3

  1. Overview of H3

    main
    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.
  2. Understand the H3Event object

    main

    In H3, every HTTP request creates an H3Event object. 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";
    });
  3. Explore H3 Utility Categories

    main

    H3 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.
  4. Quick Start with H3

    main

    To create a basic web server, instantiate a new H3 class, define routes using HTTP method helpers (like .get()), and use the serve function to start the listener on a specific port.

    import { H3, serve } from "h3";
    
    const app = new H3().get("/", (event) => "⚡️ Tadaa!");
    
    serve(app, { port: 3000 });
  5. Stream responses to the client

    main

    You 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 ReadableStream using 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 to no-cache to prevent caching of the stream.
    • Transfer-Encoding: Set to chunked to 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;
    });
  6. Mount nested H3 apps

    main

    You 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 /**:slug within a mounted app, the pathname will 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);
  7. Define dynamic and wildcard routes

    main

    H3 supports dynamic parameters and wildcard matching for flexible routing:

    • Dynamic Parameters: Use the : prefix to define named parameters. Access them via event.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 in event.context.params._ as a single string.
    SyntaxExampleMatchesDescription
    :name/hello/:name/hello/BobNamed parameter
    */hello/*/hello/anythingUnnamed optional parameter
    **/hello/**/hello/foo/barMulti-level wildcard
  8. Send errors by throwing `HTTPError`

    main

    To send specific HTTP error responses, throw an instance of HTTPError. H3 supports several ways to instantiate it:

    1. Message and Status: Provide a message string and a status code object.
    2. Static Method: Use HTTPError.status(code, statusText).
    3. Configuration Object: Pass a single object containing all error details.

    When an HTTPError is thrown, H3 returns a JSON response containing the status, statusText, message, and any additional data or body properties 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: {},
      });
    });
  9. Configure Node.js runtime for H3 v2

    main
    H3 v2 requires Node.js >= 20.11 (latest LTS recommended). While H3 v2 is ESM-only, you can still use require("h3") in CommonJS applications if you are using a recent Node.js version that supports require(esm). Alternatively, you can use compatible runtimes like Bun or Deno.
  10. Handle responses in H3 v2

    main
    In H3 v2, you should always explicitly return the response body or throw an error. Replace legacy send utilities with return statements. H3 automatically detects and handles text, JSON, streams, or web Response objects.