Skip to content

Request & Response

Every route handler receives a req (Request) and res (Response) object.

import type { Request, Response } from 'lacis'
export async function GET(req: Request, res: Response) {
res.json({ ok: true })
}

URL path parameters extracted from dynamic route segments.

// routes/users/[id]/index.ts → /users/:id
export async function GET(req: Request, res: Response) {
const { id } = req.params
res.json({ id })
}

Type: Record<string, string>


The parsed query string as a flat key-value object. Values are always strings — coerce as needed.

// GET /search?q=lacis&page=2
export async function GET(req: Request, res: Response) {
const { q, page } = req.query
res.json({ q, page: Number(page) })
}

Type: Record<string, string>


Reads and parses the request body as JSON.

interface CreateUser {
name: string
email: string
}
export async function POST(req: Request, res: Response) {
const body = await req.json<CreateUser>()
res.status(201).json({ created: body.name })
}

Signature: json<T>(): Promise<T>


Parses a multipart/form-data body. Plain fields are strings; file fields are UploadedFile objects.

export async function POST(req: Request, res: Response) {
const form = await req.form<{ name: string; avatar: UploadedFile }>()
console.log(form.name) // 'Alice'
console.log(form.avatar.size) // file size in bytes
res.status(201).json({ ok: true })
}

Signature: form<T>(): Promise<T>


Reads the raw request body as a Buffer. Useful for binary payloads or custom parsing.

export async function POST(req: Request, res: Response) {
const raw = await req.body()
const text = raw.toString('utf-8')
res.send(text)
}

Signature: body(): Promise<Buffer>

Maximum body size is 10 MB. Larger requests are rejected with 413 Payload Too Large.


Reads a single request header. Lookup is case-insensitive.

export async function GET(req: Request, res: Response) {
const auth = req.getHeader('authorization')
if (!auth) return res.status(401).json({ error: 'Unauthorized' })
res.json({ ok: true })
}

Signature: getHeader(name: string): string | undefined


Reads a single cookie from the incoming Cookie header. The value is URL-decoded automatically.

export async function GET(req: Request, res: Response) {
const sessionId = req.cookies.get('session')
if (!sessionId) return res.status(401).json({ error: 'No session' })
res.json({ session: sessionId })
}

Signature: get(name: string): string | undefined


Returns all cookies as a plain object.

export async function GET(req: Request, res: Response) {
const cookies = req.cookies.all()
res.json(cookies)
}

Signature: all(): Record<string, string>


The client’s IP address. For requests behind a reverse proxy, use the X-Forwarded-For header instead.

export async function GET(req: Request, res: Response) {
const ip = req.getHeader('x-forwarded-for') ?? req.connection.remoteAddress
res.json({ ip })
}

Serializes data to JSON, sets Content-Type: application/json, and ends the response.

res.json({ users: ['alice', 'bob'] })

Sends an HTML string with Content-Type: text/html; charset=utf-8.

res.html('<h1>Hello, world</h1>')

Sends a plain text response. If data is not a string, delegates to res.json().

res.send('pong')

Redirects the client. Default status is 302.

res.redirect('/login')
res.redirect('/new-path', 301)

Sets the HTTP status code. Chainable.

res.status(201).json({ created: true })
res.status(204).send('')

Sets a response header. Must be called before the response ends.

res.setHeader('X-Custom-Header', 'lacis')
res.json({ ok: true })

Queues a Set-Cookie header. Chainable.

res.cookies
.set('session', 'abc123', {
httpOnly: true,
secure: true,
sameSite: 'Lax',
maxAge: 60 * 60 * 24 * 7,
})
.set('theme', 'dark')
res.json({ ok: true })
OptionTypeDescription
pathstringCookie path (default: /)
domainstringCookie domain
maxAgenumberMax age in seconds
expiresDateAbsolute expiry
httpOnlybooleanPrevent JS access
securebooleanHTTPS only
sameSite'Strict' | 'Lax' | 'None'SameSite policy

Deletes a cookie by setting Max-Age: 0.

res.cookies.delete('session')
res.json({ loggedOut: true })