Context (ctx)

The Context object (ctx) is the central interface for handling HTTP requests in Jetpath. It provides:

Usage Examples

Basic Request

// Basic route handler
export const GET_user = async (ctx) => {
  // Access query parameters
  const page = ctx.query.page || '1';
  
  // Get request headers
  const authHeader = ctx.get('Authorization');
  
  // Send JSON response
  ctx.send({
    message: 'Success',
    page: parseInt(page)
  });
}

File Upload with Validation

// Using ctx.parse() for file uploads with validation
export const POST_upload = async (ctx) => {
  const data = await ctx.parse({
    maxBodySize: 10 * 1024 * 1024, // 10MB limit
    contentType: 'multipart/form-data'
  });
  
  // Validate file data
  if (!data.files || !data.files.file) {
    ctx.send( 'No file uploaded',400);
    return
  }
   
  ctx.send({ message: 'Files uploaded successfully' });

}

WebSocket Connection

// WebSocket route handler
export const GET_live = async (ctx) => {
  // Upgrade to WebSocket
  ctx.upgrade();
  
  // Access WebSocket connection
  const conn = ctx.connection!;
  
  // Handle WebSocket events
  conn.addEventListener('message', (data) => {
    // Handle incoming messages
  });
  
  conn.addEventListener('close', () => {
    // Handle connection close
  });

}

Best Practices

  1. Type Safety: Use generics to define expected data shapes
  2. Error Handling: Use ctx.send(error, <http status code>) for HTTP errors
  3. State Management: Use ctx.state for request-scoped data and attach user info if authenticated
  4. Security: Always validate input data and implement proper authentication
  5. Response Handling: Use appropriate methods for different response types and include request ID in headers
  6. Logging: Use ctx.plugins.logger for detailed request logging with request ID and duration
  7. Headers: Add standard response headers including X-Request-ID and X-Response-Time

Key Features

Request Data Access

Response Handling

Navigation

Headers & Cookies

WebSocket

Additional Properties

}

ctx.send(user);

}


### File Upload

```typescript
// Using ctx.parse() for file uploads
export const POST_upload = async (ctx) => {
    const data = await ctx.parse({
      maxBodySize: 10 * 1024 * 1024, // 10MB limit
      contentType: 'multipart/form-data'
    });
    
    // Handle uploaded files
    // data.files contains uploaded files
    ctx.send({ message: 'Files uploaded successfully' });
}

Best Practices

  1. Type Safety: Use generics to define expected data shapes
  2. State Management: Use ctx.state for request-scoped data
  3. Security: Always validate input data
  4. Response Handling: Use appropriate methods for different response types

Next Steps

plugins: UnionToIntersection<JetPluginTypes[number]> & Record<string, any>

body: Promise<Record<string, any>>

query: Record<string, string | string[]>

params: Record<string, string>

// Using ctx.parse() for file uploads with validation export const POST_upload = async (ctx) => { const data = await ctx.parse({ maxBodySize: 10 * 1024 * 1024, // 10MB limit contentType: ‘multipart/form-data’ });

// Validate file data if (!data.files || !data.files.file) { ctx.send( ‘No file uploaded’,400); return }

ctx.send({ message: ‘Files uploaded successfully’ });

}

    // Route: /live
    export const GET_live: JetRoute = (ctx) => {
      ctx.upgrade();
      const conn = ctx.connection!; // Assert non-null for WS routes
      console.log("Client connected via WebSocket");

      conn.addEventListener("open", (socket) => {
        socket.send("Welcome to the live feed!");
      });

      conn.addEventListener("message", (socket, event) => {
        console.log("Received message:", event.data);
        socket.send(`You sent: ${event.data}`);
      });

      conn.addEventListener("close", () => {
        console.log("Client disconnected");
      });
    };
    ```
    *[cite: tests/app.jet.ts]*

### `request: Request`

  * **Type:** `Request` (Web Standard)
  * **Description:** Access the underlying standard `Request` object. Useful for lower-level access to request details like headers map, method, URL object, or potentially reading the raw body stream.
  * **Example:**
    ```typescript
    const method = ctx.request.method; // "GET", "POST", etc.
    const url = new URL(ctx.request.url);
    const pathname = url.pathname;
    // Potentially access raw body: const reader = ctx.request.body?.getReader();
    ```

### `code: number`

  * **Type:** `number`
  * **Description:** Gets or sets the HTTP status code for the outgoing response. Modify this before calling `ctx.send` or `ctx.throw` to control the response status. Defaults to `200` if `ctx.send` is called without errors.
  * **Example 1: Setting Success Code**
    ```typescript
    // After creating a resource:
    ctx.code = 201; // Created
    ctx.send({ id: newResourceId, message: "Resource created" });
    ```
  * **Example 2: Setting Error Code Before Throwing**
    ```typescript
    if (!resource) {
      ctx.code = 404; // Set explicit 404
      ctx.send("Resource not found"); // Middleware will use ctx.code (404)
    }
    ```
    *[cite: tests/app.jet.ts (used extensively)]*

### `path: string`

  * **Type:** `string`
  * **Description:** Contains the pathname part of the request URL, excluding the query string.
  * **Example:**
    ```typescript
    // For URL: /users/profile?edit=true
    const pathname = ctx.path; // "/users/profile"
    ```

-----

## Methods

Methods returning `never` indicate they terminate the request flow.

### `eject(): never`

  * **Description:** Disconnects Jetpath's automatic response handling. Use this advanced feature only when you need full manual control over the response stream, often for integrating with libraries that directly pipe to the underlying response (like older versions of `busboy` on Node.js). After `eject()`, Jetpath will *not* send any response automatically; your code is entirely responsible.
  * **Example:** *(Refer to specific streaming library documentation for usage after ejecting)*
 

### `sendStream(stream: ReadableStream | any, ContentType: string): never`

  * **Description:** Sends a `ReadableStream` as the response body. Ideal for large files or dynamically generated content. Requires setting the correct `Content-Type`.
  * **Example:**
    ```typescript
 ctx.sendStream(file name);
    ``` 

### `sendResponse(response?: Response): never`

  * **Description:** Sends a raw Web Standard `Response` object directly. Bypasses Jetpath's content negotiation and serialization. Useful for maximal control, especially in Deno/Bun.
  * **Example:**
    ```typescript 
    ctx.sendResponse(response);
    ```

### `send(data: unknown, ContentType?: string): never`

  * **Description:** The primary method for sending responses. Handles serialization and content type automatically for common types.
  * **Example 1: Sending JSON (Default)**
    ```typescript
    ctx.send({ status: "success", data: { userId: 123 } });
    // -> Content-Type: application/json
    ```
  * **Example 2: Sending HTML**
    ```typescript
    const html = "<h1>Hello from Jetpath!</h1>";
    ctx.send(html, "text/html");
    // -> Content-Type: text/html
    ```
  * **Example 3: Sending Plain Text**
    ```typescript
    ctx.send("OK");
    // -> Content-Type: text/plain
    ```typescript
// WebSocket route handler
export const GET_live = async (ctx) => {
  // Upgrade to WebSocket
  ctx.upgrade();
  
  // Access WebSocket connection
  const conn = ctx.connection!;
  
  // Handle WebSocket events
  conn.addEventListener('message', (data) => {
    // Handle incoming messages
  });
  
  conn.addEventListener('close', () => {
    // Handle connection close
  });

}
```0typescript
    // If pet with ctx.params.id doesn't exist:
    ctx.send(`Pet with ID ${ctx.params.id} not found`, 404);
    ```
  * **Example 2: Unauthorized**
    ```typescript
    // If authentication fails:
    ctx.set("WWW-Authenticate", "Bearer realm=\"protected area\""); // Add relevant header
    ctx.send("Invalid credentials", 401);
    ``` 
  * **Example 3: Internal Server Error**
    ```typescript
    try { /* some risky operation */ }
    catch (err) {
      console.error("Unexpected error:", err);
      ctx.send("",500); // Let middleware handle generic message
    }
    ```

### `redirect(url: string, code: number = 302): never` *(Assuming optional code)*

  * **Description:** Sends a redirect response to the client. Sets the `Location` header to the provided `url` and sets the status code (defaults typically to 302 Found).
  * **Example:**
    ```typescript
    // After successful login or form submission:
    ctx.redirect("/dashboard");

    // For a permanent redirect:
    // ctx.redirect("/new-location", 301);
    ```

### `get(field: string): string | undefined`

  * **Description:** Reads a request header value (case-insensitive).
  * **Example:**
    ```typescript
    const userAgent = ctx.get("User-Agent");
    const acceptEncoding = ctx.get("Accept-Encoding");
    const customHeader = ctx.get("X-Custom-ID");
    ```

### `set(field: string, value: string): void`

  * **Description:** Sets a response header value. Can be called multiple times.
  * **Example:**
    ```typescript
    ctx.set("Content-Language", "en-US");
    ctx.set("Cache-Control", "public, max-age=3600");
    ctx.set("X-Powered-By", "Jetpath"); // Add a custom header
    ```

### `parse(options?: { maxBodySize?: number; contentType?: string }): Promise<Record<string, any>>`

  * **Description:** Asynchronously reads and parses the request body specifically as JSON. Populates `ctx.body` upon success. Throws if the body is not valid JSON or has already been consumed. It's often called just before `ctx.validate()` if not using eager pre-processing.
  * **Example:**
    ```typescript
    // In a POST handler expecting JSON:
    async function handler(ctx) {
        try { 
            const name = (await ctx.parse()).name;
            ctx.send({ received: name });
        } catch (err) {
            ctx.send(`Invalid JSON payload: ${err.message}`,400);
        }
    }
    ```

-----

## Next Steps

  * See how `ctx` is used throughout the [**Request Lifecycle**](./request-lifecycle.md).
  * Learn how [**Middleware**](./middleware.md) leverages `ctx` for cross-cutting concerns.
  * Understand how [**Validation**](./validation.md) uses schemas to type and check `ctx.parse()`, `ctx.parseQuery()`, and `ctx.params`.
 
 

</docmach>