He
HeliumTS
Note:

HeliumTS is under pre-beta and active development. Expect bugs and breaking changes. If you find any issues, please report them in our GitHub

A stable release is planned for early December 2025.

HTTP Handlers

Overview

HeliumTS provides defineHTTPRequest for creating custom HTTP endpoints. This is useful for:

  • Webhooks (Stripe, GitHub, etc.)
  • REST APIs
  • Third-party integrations (Auth providers)
  • File uploads/downloads
  • Server-sent events

In this section:

  • Examples - Stripe webhooks, OpenAI streaming, auth handlers

Basic Usage

1import { defineHTTPRequest } from "heliumts/server";
2
3export const myEndpoint = defineHTTPRequest("GET", "/api/hello", async (req, ctx) => {
4 return { message: "Hello World" };
5});

Supported methods: GET, POST, PUT, PATCH, DELETE, ALL

Dynamic Routes

Use :param syntax for dynamic path segments:

1export const getUser = defineHTTPRequest("GET", "/api/users/:id", async (req, ctx) => {
2 const userId = req.params.id;
3 const user = await db.users.findById(userId);
4 return { user };
5});
6
7// Multiple parameters
8export const getProduct = defineHTTPRequest("GET", "/api/products/:category/:id", async (req, ctx) => {
9 const { category, id } = req.params;
10 return { category, id };
11});

Catch-All Routes

Use * to match any remaining path segments (useful for auth providers):

1import { defineHTTPRequest } from "heliumts/server";
2import { auth } from "./auth"; // Better Auth or similar
3
4// Matches /api/auth/signin, /api/auth/signout, /api/auth/callback/google, etc.
5export const authHandler = defineHTTPRequest("ALL", "/api/auth/*", async (req, ctx) => {
6 const webRequest = await req.toWebRequest();
7 return auth.handler(webRequest);
8});

Request Object

1export const myHandler = defineHTTPRequest("POST", "/api/data", async (req, ctx) => {
2 // HTTP method
3 console.log(req.method); // "POST"
4
5 // Headers
6 const contentType = req.headers["content-type"];
7
8 // Query parameters
9 const search = req.query.q;
10
11 // Route parameters
12 const id = req.params.id;
13
14 // Cookies
15 const sessionId = req.cookies.sessionId;
16
17 // Parse JSON body
18 const body = await req.json();
19
20 // Parse text body
21 const text = await req.text();
22
23 return { success: true };
24});

Request Properties

  • req.method - HTTP method (GET, POST, etc.)
  • req.headers - Request headers object
  • req.query - Query string parameters
  • req.params - Route parameters
  • req.cookies - Parsed cookies
  • req.json() - Parse JSON body
  • req.text() - Get raw body as text
  • req.toWebRequest() - Convert to Web API Request

Response Headers & Status Codes

Return a standard Web API Response object for full control:

1export const customHeaders = defineHTTPRequest("GET", "/api/data", async (req, ctx) => {
2 const data = { message: "Hello World" };
3
4 return new Response(JSON.stringify(data), {
5 status: 200,
6 headers: {
7 "Content-Type": "application/json",
8 "Cache-Control": "max-age=3600",
9 "X-Custom-Header": "my-value",
10 },
11 });
12});
13
14// Error response
15export const errorExample = defineHTTPRequest("POST", "/api/resource", async (req, ctx) => {
16 const body = await req.json();
17
18 if (!body.email) {
19 return new Response(JSON.stringify({ error: "Email required" }), {
20 status: 400,
21 headers: { "Content-Type": "application/json" },
22 });
23 }
24
25 return { success: true };
26});

Common Status Codes

  • 200 - OK
  • 201 - Created
  • 400 - Bad Request
  • 401 - Unauthorized
  • 403 - Forbidden
  • 404 - Not Found
  • 500 - Internal Server Error

Streaming Responses

1export const streamData = defineHTTPRequest("GET", "/api/stream", async (req, ctx) => {
2 const stream = new ReadableStream({
3 async start(controller) {
4 for (let i = 0; i < 10; i++) {
5 controller.enqueue(`data: ${i}\n\n`);
6 await new Promise((resolve) => setTimeout(resolve, 1000));
7 }
8 controller.close();
9 },
10 });
11
12 return new Response(stream, {
13 status: 200,
14 headers: {
15 "Content-Type": "text/event-stream",
16 "Cache-Control": "no-cache",
17 Connection: "keep-alive",
18 },
19 });
20});

Converting to Web Request

Use toWebRequest() to convert Helium's request to a standard Web API Request for third-party libraries:

1import { defineHTTPRequest } from "heliumts/server";
2import { auth } from "./auth"; // Better Auth or similar
3
4export const authHandler = defineHTTPRequest("ALL", "/auth/*", async (req, ctx) => {
5 // Convert to Web Request for third-party libraries
6 const webRequest = await req.toWebRequest();
7
8 // Pass to third-party handler
9 return auth.handler(webRequest);
10});

Best Practices

  • Use Response objects when you need custom headers or status codes
  • Set appropriate HTTP status codes for different scenarios
  • Always validate request data before processing
  • Verify webhook signatures for security
  • Add cache headers for cacheable responses
  • Handle errors gracefully with try-catch blocks