Skip to content

Context

Every handler and middleware in GamanJS receives a ctx (Context) object containing all request information and utilities for accessing data.

URL pathname (without query string):

// Request: GET /users/123?active=true
ctx.path; // '/users/123'

Full URL instance:

ctx.url.origin; // 'http://localhost:3431'
ctx.url.pathname; // '/users/123'
ctx.url.search; // '?active=true'

Raw request information:

ctx.request.id; // Unique request ID (auto-generated)
ctx.request.method; // 'GET', 'POST', etc
ctx.request.url; // Full URL as string
ctx.request.pathname; // Pathname
ctx.request.body(); // Promise<Buffer> — raw body

Get a single route parameter:

// Route: /users/:id
r.get('/users/:id', (ctx) => {
const id = ctx.param('id'); // '123'
return Res.send({ id });
});

All route parameters as an object:

// Route: /posts/:postId/comments/:commentId
ctx.params; // { postId: '1', commentId: '42' }

Access query parameters directly:

// Request: GET /search?q=gaman&page=2
ctx.query.q; // 'gaman'
ctx.query.page; // '2'

For parameters with multiple values:

// Request: GET /filter?tag=js&tag=ts
ctx.query.tag; // ['js', 'ts']

Parse body as JSON:

async Create(ctx) {
const body = await ctx.json<{ name: string; email: string }>();
// body.name, body.email
return Res.send(body, 201);
}

Read body as plain text:

async Webhook(ctx) {
const raw = await ctx.text();
return Res.message('OK');
}

Parse body as FormData (multipart or URL-encoded):

async Upload(ctx) {
const form = await ctx.formData();
const name = form.get('name');
// ...
}

Get a single string value from form data:

const email = await ctx.input('email'); // string | null

Get multiple string values from form data:

const tags = await ctx.inputs('tags'); // string[]

Get a single file from form data:

const avatar = await ctx.file('avatar'); // GFile | null
if (avatar) {
avatar.name; // original file name
avatar.type; // MIME type
avatar.size; // size in bytes
// ...
}

Get multiple files from form data:

const images = await ctx.files('images'); // GFile[]

Get a specific header value (case-insensitive):

const token = ctx.header('Authorization'); // string | null
const contentType = ctx.header('Content-Type');

GamanHeader instance for reading and manipulating headers:

// Read
ctx.headers.get('Content-Type');
// Set response header
ctx.headers.set('X-Custom-Header', 'value');

Bun’s CookieMap instance for accessing cookies:

const session = ctx.cookies.get('session_id');

Middleware and handlers can share data via the context store:

ctx.set('user', { id: 1, name: 'Angga' });
const user = ctx.get<{ id: number; name: string }>('user');
if (ctx.has('user')) {
// user was set by middleware
}
ctx.delete('tempData');

export default composeController(() => ({
async CreatePost(ctx) {
// Route params
const userId = ctx.param('userId');
// Query
const draft = ctx.query.draft === 'true';
// Body
const body = await ctx.json<{
title: string;
content: string;
}>();
// Headers
const token = ctx.header('Authorization');
// Data from middleware
const currentUser = ctx.get('user');
return Res.send({
userId,
draft,
title: body.title,
author: currentUser.name,
}, 201);
},
}));