Minimal H(TTP) framework built for high performance and portability across multiple JavaScript runtimes.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Response utilities for sending different content types, redirects, status codes, streaming responses, and converting values to standard Response objects.
Convert various return values to standard Response objects.
/**
* Convert any value to a Response object
* @param val - Value to convert (object, string, Response, etc.)
* @param event - H3 event context
* @param config - Optional H3 configuration
* @returns Response object or Promise resolving to Response
*/
function toResponse(val: unknown, event: H3Event, config?: H3Config): Response | Promise<Response>;Usage Examples:
import { toResponse } from "h3";
// Convert various types
const handler = defineHandler(async (event) => {
// Objects become JSON responses
const jsonResponse = await toResponse({ message: "Hello" }, event);
// Strings become text responses
const textResponse = await toResponse("Hello World", event);
// Numbers become text responses
const numberResponse = await toResponse(42, event);
// Arrays become JSON responses
const arrayResponse = await toResponse([1, 2, 3], event);
// Response objects pass through
const customResponse = await toResponse(
new Response("Custom", { status: 201 }),
event
);
return jsonResponse;
});Send status codes, redirects, and empty responses.
/**
* Send a redirect response
* @param event - H3 event
* @param location - Redirect URL
* @param code - HTTP status code (default: 302)
* @returns Redirect location string
*/
function redirect(event: H3Event, location: string, code?: number): string;
/**
* Send an empty response with optional status code
* @param event - H3 event
* @param code - HTTP status code (default: 204)
* @returns Empty Response object
*/
function noContent(event: H3Event, code?: number): Response;Usage Examples:
import { redirect, noContent } from "h3";
// Redirect responses
const redirectHandler = defineHandler((event) => {
const { type } = getQuery(event);
if (type === "permanent") {
return redirect(event, "/new-location", 301);
} else {
return redirect(event, "/temporary-location", 302);
}
});
// Empty responses
const deleteHandler = defineHandler((event) => {
const id = getRouterParam(event, "id");
deleteResource(id);
return noContent(event, 204); // No Content
});
// Custom status codes
const acceptedHandler = defineHandler((event) => {
processAsync(event);
return noContent(event, 202); // Accepted
});Send specific content types with proper headers.
/**
* Send HTML content with proper content-type header
* @param event - H3 event
* @param content - HTML string content
* @returns HTML content string
*/
function html(event: H3Event, content: string): string;Usage Examples:
import { html } from "h3";
// HTML responses
const pageHandler = defineHandler((event) => {
const page = `
<!DOCTYPE html>
<html>
<head><title>My Page</title></head>
<body>
<h1>Welcome</h1>
<p>This is a dynamic page.</p>
</body>
</html>
`;
return html(event, page);
});
// Dynamic HTML
const dynamicHandler = defineHandler((event) => {
const { name } = getQuery(event);
const content = `
<html>
<body>
<h1>Hello, ${name || 'Guest'}!</h1>
</body>
</html>
`;
return html(event, content);
});Stream data using async iterables and generators.
/**
* Stream iterable content as a response
* @param event - H3 event
* @param iterable - Async iterable or generator
* @param options - Streaming options
* @returns ReadableStream for streaming response
*/
function iterable<Value, Return = any>(
event: H3Event,
iterable: IterationSource<Value, Return>,
options?: IterableOptions<Value>
): ReadableStream;
interface IterableOptions<Value = any> {
/**
* Serializer function for values
*/
serializer?: (value: Value) => string | Uint8Array;
/**
* Separator between values
*/
separator?: string;
/**
* Content type header
*/
contentType?: string;
}
type IterationSource<Value, Return = any> =
| Iterable<Value>
| AsyncIterable<Value>
| Generator<Value, Return>
| AsyncGenerator<Value, Return>;Usage Examples:
import { iterable } from "h3";
// Stream array data
const streamArrayHandler = defineHandler((event) => {
const data = [1, 2, 3, 4, 5];
return iterable(event, data, {
serializer: (value) => JSON.stringify(value),
separator: "\n",
contentType: "application/x-ndjson"
});
});
// Stream with async generator
const streamAsyncHandler = defineHandler((event) => {
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield { id: i, timestamp: Date.now() };
}
}
return iterable(event, generateData(), {
serializer: (value) => JSON.stringify(value) + "\n"
});
});
// Stream large dataset
const streamDatabaseHandler = defineHandler((event) => {
async function* streamRecords() {
const cursor = database.cursor();
for await (const record of cursor) {
yield record;
}
}
return iterable(event, streamRecords(), {
serializer: JSON.stringify,
separator: ",\n",
contentType: "application/json"
});
});
// Stream file lines
const streamFileHandler = defineHandler((event) => {
const filePath = getRouterParam(event, "file");
async function* readLines() {
const file = await fs.open(filePath, "r");
const stream = file.createReadStream();
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
yield new TextDecoder().decode(value);
}
} finally {
reader.releaseLock();
await file.close();
}
}
return iterable(event, readLines());
});Send HTTP/1.1 103 Early Hints for performance optimization.
/**
* Write HTTP/1.1 103 Early Hints response
* @param event - H3 event
* @param hints - Object with link relations and URLs
* @returns void or Promise<void>
*/
function writeEarlyHints(
event: H3Event,
hints: Record<string, string>
): void | Promise<void>;Usage Examples:
import { writeEarlyHints } from "h3";
// Send early hints for performance
const pageWithHintsHandler = defineHandler(async (event) => {
// Send early hints to help browser preload resources
await writeEarlyHints(event, {
"preload": "</styles.css>; rel=preload; as=style",
"preconnect": "<https://api.example.com>; rel=preconnect"
});
// Process the actual response
const data = await fetchPageData();
return html(event, `
<html>
<head>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>${data.title}</h1>
</body>
</html>
`);
});
// Early hints for API responses
const apiWithHintsHandler = defineHandler(async (event) => {
await writeEarlyHints(event, {
"preload": "</api/user>; rel=preload; as=fetch",
"preload": "</api/settings>; rel=preload; as=fetch"
});
const [user, settings] = await Promise.all([
fetchUser(),
fetchSettings()
]);
return { user, settings };
});Set custom headers and status codes on responses.
// Example patterns for custom responses
const customHeadersHandler = defineHandler((event) => {
// Set custom headers using event.res
event.res.setHeader("X-API-Version", "1.0");
event.res.setHeader("Cache-Control", "max-age=3600");
event.res.setStatus(201);
return { created: true };
});Usage Examples:
// CORS headers
const corsHandler = defineHandler((event) => {
event.res.setHeader("Access-Control-Allow-Origin", "*");
event.res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
event.res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return { message: "CORS enabled" };
});
// Cache control
const cachedHandler = defineHandler((event) => {
const isPublic = getQuery(event).public === "true";
if (isPublic) {
event.res.setHeader("Cache-Control", "public, max-age=3600");
} else {
event.res.setHeader("Cache-Control", "private, no-cache");
}
return { data: "cached response" };
});
// Custom status codes
const statusHandler = defineHandler((event) => {
const { action } = getQuery(event);
switch (action) {
case "create":
event.res.setStatus(201);
return { created: true };
case "accept":
event.res.setStatus(202);
return { accepted: true };
default:
event.res.setStatus(200);
return { success: true };
}
});Send file downloads with proper headers.
// Example file download pattern
const downloadHandler = defineHandler(async (event) => {
const filename = getRouterParam(event, "filename");
const filePath = path.join("/uploads", filename);
// Check file exists
if (!await fs.exists(filePath)) {
throw HTTPError.status(404, "File not found");
}
// Set download headers
event.res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
event.res.setHeader("Content-Type", "application/octet-stream");
// Stream file
const fileStream = fs.createReadStream(filePath);
return new Response(fileStream);
});Handle response compression and encoding.
// Example compression pattern
const compressedHandler = defineHandler((event) => {
const acceptEncoding = event.req.headers.get("accept-encoding") || "";
if (acceptEncoding.includes("gzip")) {
event.res.setHeader("Content-Encoding", "gzip");
}
const largeData = generateLargeDataset();
return { data: largeData };
});/**
* Response configuration options
*/
interface ResponseConfig {
/**
* Default status code
*/
status?: number;
/**
* Default headers
*/
headers?: Record<string, string>;
/**
* Serialization options
*/
serializer?: (value: any) => string | Uint8Array;
}
/**
* Iteration source type for streaming
*/
type IterationSource<Value, Return = any> =
| Iterable<Value>
| AsyncIterable<Value>
| Generator<Value, Return>
| AsyncGenerator<Value, Return>;Transform responses based on content type or other criteria.
// Example response transformer
const transformerHandler = defineHandler(async (event) => {
const accept = event.req.headers.get("accept");
const data = { message: "Hello", timestamp: Date.now() };
if (accept?.includes("application/xml")) {
event.res.setHeader("Content-Type", "application/xml");
return `<response><message>${data.message}</message><timestamp>${data.timestamp}</timestamp></response>`;
}
return data; // Default JSON
});Send different responses based on conditions.
// Example conditional response
const conditionalHandler = defineHandler((event) => {
const userAgent = event.req.headers.get("user-agent") || "";
const isMobile = /Mobile|Android|iPhone/i.test(userAgent);
if (isMobile) {
return html(event, `
<html>
<meta name="viewport" content="width=device-width">
<body><h1>Mobile Version</h1></body>
</html>
`);
}
return html(event, `
<html>
<body><h1>Desktop Version</h1></body>
</html>
`);
});