API Routes
Export named HTTP method handlers from files in server/ and they become fully typed API endpoints.
Creating a route
Create a .ts file in server/ and export named functions matching HTTP methods. The file path maps to the URL the same way pages do:
server/users/index.ts → GET /users, POST /userstypescript
import type { ApiRequest, ApiResponse } from 'nukejs'
export async function GET(req: ApiRequest, res: ApiResponse) {
const users = await db.getUsers()
res.json(users)
}
export async function POST(req: ApiRequest, res: ApiResponse) {
const user = await db.createUser(req.body)
res.json(user, 201)
}Dynamic API routes
Use [param] in the filename. Route params land in req.params:
server/users/[id].ts → /users/:idtypescript
import type { ApiRequest, ApiResponse } from 'nukejs'
export async function GET(req: ApiRequest, res: ApiResponse) {
const { id } = req.params as { id: string }
const user = await db.getUser(id)
if (!user) {
res.json({ error: 'Not found' }, 404)
return
}
res.json(user)
}
export async function PUT(req: ApiRequest, res: ApiResponse) {
const { id } = req.params as { id: string }
const updated = await db.updateUser(id, req.body)
res.json(updated)
}
export async function DELETE(req: ApiRequest, res: ApiResponse) {
await db.deleteUser(req.params.id as string)
res.status(204).end()
}Request object
| Property | Type | Description |
|---|---|---|
| req.body | any | Parsed JSON body (or raw string). Up to 10 MB. |
| req.params | Record<string, string | string[]> | Dynamic path segments |
| req.query | Record<string, string> | URL search params |
| req.method | string | HTTP method (GET, POST, …) |
| req.headers | IncomingHttpHeaders | Raw request headers |
Response object
| Method | Description |
|---|---|
| res.json(data, status?) | Send JSON. Default status 200. |
| res.status(code) | Set status code, returns res for chaining. |
| res.setHeader(name, value) | Set a response header. |
| res.end(body?) | Send a raw response and close. |
Query string parameters
server/search.ts → GET /search?q=nuke&page=2typescript
export async function GET(req: ApiRequest, res: ApiResponse) {
const { q = '', page = '1' } = req.query
const results = await search(q, parseInt(page))
res.json({ results, page: parseInt(page) })
}Calling API logic from pages
Because pages are server components, you can import and call your database layer directly — skipping the HTTP round-trip entirely:
app/pages/users.tsxtypescript
import { getUsers } from '../../lib/db' // import DB directly
export default async function UsersPage() {
const users = await getUsers() // no fetch() needed
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
)
}API routes are for your frontend clientsServer-rendered pages can call database code directly. API routes are most useful for client components making
fetch() calls, or for third-party integrations consuming your endpoints.