Building Your App
Route Handlers
API endpoints, Server-Sent Events, and WebSockets with route.ts files.
A route.ts (or route.js) file turns its folder into a server endpoint. Export a function per HTTP method - GET, POST, PUT, PATCH, DELETE:
ts
// app/api/notes/[id]/route.ts
import type { GioRequest } from '@gio.js/core';
export async function POST(req: GioRequest) {
const { text } = req.json<{ text: string }>();
const user = req.cookies['session']; // parsed Cookie header
const id = req.params['id']; // from the [id] segment
return { saved: text, id }; // → application/json, 200
}The request object
Handlers receive a GioRequest: method, path, params, query, lowercased headers, parsed cookies, the raw body (bodyBase64 is true for binary bodies), and a json() helper.
What you can return
- Any JSON-serializable value - sent as
application/jsonwith status 200. - A web-standard
Response- its status, headers, and body pass through. null/undefined- 204 No Content.- A
GioEventStream(GET only) - switches the connection to SSE.
ts
export function DELETE() {
return new Response('gone', { status: 202, headers: { 'X-Reason': 'cleanup' } });
}Server-Sent Events
ts
// app/ticker/route.ts
import { GioEventStream } from '@gio.js/core';
export function GET() {
return new GioEventStream((stream) => {
const t = setInterval(() => stream.send({ time: Date.now() }), 1000);
return () => clearInterval(t); // runs when the client disconnects
});
}Rules
- Handler responses are never cached or coalesced - every request runs your code.
- Requests for methods you didn't export get
405with anAllowheader. - A GET without a GET handler falls through to a sibling
page.tsxif one exists. - Pages only answer GET/HEAD - mutations belong in route handlers.
- A thrown error is logged server-side and answered with a JSON 500 (no internals leaked).
- Export
wsHandlerfrom the same file for WebSockets - see the WebSockets page.