# How to Define GET Requests in 9router API Routes

> Learn to define GET requests in 9router API routes. Export an async GET function from route.js and return a Web Response object. Master 9router API development.

- Repository: [decolua/9router](https://github.com/decolua/9router)
- Tags: how-to-guide
- Published: 2026-05-08

---

**In 9router, you define GET endpoints by exporting an async function named `GET` from a [`route.js`](https://github.com/decolua/9router/blob/main/route.js) file located inside your App Router directory structure, returning a standard Web `Response` object.**

9router (decolua/9router) is built on Next.js 13's App Router, where each API endpoint corresponds to a physical file path under `src/app/api/`. This file-based routing system maps HTTP methods directly to exported JavaScript functions, making it straightforward to define GET requests for fetching data, handling query parameters, and managing dynamic URL segments.

## The Route File Conventions

Every API route in 9router resides in a [`route.js`](https://github.com/decolua/9router/blob/main/route.js) (or [`route.ts`](https://github.com/decolua/9router/blob/main/route.ts)) file within the App Router structure. The framework automatically maps the file path to a URL endpoint and the exported function names to HTTP verbs.

Key conventions from the source code include:

- **File location**: `src/app/api/[endpoint]/route.js`
- **Function naming**: Export async functions matching HTTP methods (`GET`, `POST`, `OPTIONS`)
- **Response format**: Return standard Web API `Response` objects or use `Response.json()` for JSON payloads

## Basic GET Handler Structure

The fundamental pattern for defining GET requests in 9router follows this signature:

```javascript
export async function GET(request, { params }) {
  // Handler logic here
  return Response.json({ data: "your data" });
}

```

The function accepts two arguments:
- `request`: The standard Web Request object containing headers, URL, and body
- `params`: An object containing dynamic route parameters (for routes with `[slug]` segments)

According to the implementation in [`src/app/api/health/route.js`](https://github.com/decolua/9router/blob/main/src/app/api/health/route.js), the simplest health check endpoint requires minimal boilerplate:

```javascript
export async function GET() {
  return new Response("OK", { status: 200 });
}

```

## Handling Static Routes with Business Logic

For endpoints that fetch and transform data, the GET handler typically integrates with internal helpers and includes comprehensive error handling. The models list endpoint in [`src/app/api/v1/models/route.js`](https://github.com/decolua/9router/blob/main/src/app/api/v1/models/route.js) demonstrates this pattern:

```javascript
export async function GET() {
  try {
    const data = await buildModelsList([LLM_KIND]);
    return Response.json(
      { object: "list", data },
      {
        headers: { "Access-Control-Allow-Origin": "*" },
      }
    );
  } catch (error) {
    console.log("Error fetching models:", error);
    return Response.json(
      { error: { message: error.message, type: "server_error" } },
      { status: 500 }
    );
  }
}

```

This implementation shows the standard 9router approach: wrap business logic in a `try/catch` block, call helper functions like `buildModelsList` to gather data, and return JSON with CORS headers for cross-origin compatibility.

## Dynamic URL Parameters

When defining GET requests with dynamic segments (such as `/v1/models/:kind`), 9router uses square bracket notation in the directory name, like `[kind]/route.js`. The parameter values are accessed through the second argument's `params` property.

In `src/app/api/v1/models/[kind]/route.js`, the handler extracts and validates the dynamic segment:

```javascript
export async function GET(_request, { params }) {
  const { kind } = await params;
  const kindFilter = KIND_SLUG_MAP[kind];
  
  if (!kindFilter) {
    return Response.json(
      { error: { message: `Unknown model kind: ${kind}` } }, 
      { status: 404 }
    );
  }
  
  const data = await buildModelsList(kindFilter);
  return Response.json(
    { object: "list", data }, 
    { headers: { "Access-Control-Allow-Origin": "*" } }
  );
}

```

Note that `params` is awaited as a Promise in the current Next.js App Router implementation, ensuring dynamic parameters are resolved before use.

## Query Parameter Handling

For GET requests that filter or lookup resources via query strings (like `?id=123`), parse the URL from the request object. The model info endpoint in [`src/app/api/v1/models/info/route.js`](https://github.com/decolua/9router/blob/main/src/app/api/v1/models/info/route.js) illustrates this technique:

```javascript
export async function GET(request) {
  const searchParams = new URL(request.url).searchParams;
  const id = searchParams.get("id");
  
  // Lookup logic based on id
  // ...
  
  return Response.json(
    { id, /* other properties */ }, 
    { headers: { "Access-Control-Allow-Origin": "*" } }
  );
}

```

This approach uses the standard Web API `URL` constructor to extract `searchParams`, making it compatible with Edge runtime environments.

## CORS and Preflight Configuration

Production 9router deployments typically export an `OPTIONS` handler alongside GET functions to handle CORS preflight requests. While not strictly part of the GET definition, this pattern appears consistently across route files to ensure the `Access-Control-Allow-Origin` header is properly set for all methods.

## Summary

- **File-based routing**: Create [`route.js`](https://github.com/decolua/9router/blob/main/route.js) files under `src/app/api/` where the directory structure defines the URL path.
- **Named exports**: Export an async function literally named `GET` to handle GET requests in 9router.
- **Signature**: Accept `(request, { params })` where `params` contains dynamic route segments.
- **Response handling**: Return `Response.json()` or `new Response()`, always including appropriate CORS headers for API compatibility.
- **Error boundaries**: Wrap data fetching logic in `try/catch` blocks to return structured 500 error responses rather than unhandled exceptions.
- **Query access**: Use `new URL(request.url).searchParams` to extract filter parameters from the request URL.

## Frequently Asked Questions

### Can I export multiple HTTP methods from the same route file?

Yes. A single [`route.js`](https://github.com/decolua/9router/blob/main/route.js) file can export multiple handler functions such as `GET`, `POST`, and `OPTIONS`. 9router automatically routes incoming requests to the function matching the HTTP method, allowing you to consolidate related endpoint logic in one location.

### How do I access headers in a GET handler?

Access headers through the `request` object's `headers` property, which returns a `Headers` instance. For example: `request.headers.get('authorization')`. This standard Web API approach works consistently across all 9router GET implementations.

### What happens if I don't export a GET function for a route?

If the client sends a GET request to a route that exists but lacks a `GET` export, Next.js returns a `405 Method Not Allowed` response. This behavior ensures that only explicitly defined HTTP methods are exposed on your API endpoints, preventing accidental data leakage from undefined routes.