Skip to content

Responses

In GamanJS v2, the primary way to send a response is using ctx.send(). This method provides a fluent interface to create and customize HTTP responses easily.

The ctx.send() method takes two optional arguments: data and status. It returns a GamanResponseBuilder which you can use to finalize the response.

// Send JSON with status 200 (default)
return ctx.send({ name: 'GamanJS', version: '2.0' }).ok();
// Send with a different status
return ctx.send({ error: 'Conflict' }).conflict();
// Send with a custom status using .build()
return ctx.send({ message: 'Success' }).build(200);

ctx.send() automatically detects the content type based on the data provided:

  • Object/Array: Sent as application/json.
  • String (HTML): If the string starts with < and ends with >, it’s sent as text/html.
  • String (Plain): Sent as text/plain.
  • Buffer/Blob: Sent with the appropriate binary content type (if detectable) or application/octet-stream.

[!IMPORTANT] ctx.send() does not accept a header configuration object. To set response headers, you must use the ctx.headers API before calling ctx.send().

// Set a header
ctx.headers.set('X-Custom-Header', 'GamanJS-v2');
// Set multiple headers
ctx.headers.set('Content-Type', 'application/pdf');
return ctx.send(pdfBuffer).ok();

The GamanResponseBuilder provides several semantic methods for common HTTP status codes:

MethodStatus CodeDescription
.ok()200Standard success response.
.created()201Resource successfully created.
.accepted()202Request received but still processing.
.noContent()204Success with no response body.

[!NOTE] Some error methods like .unauthorized(), .forbidden(), and .notFound() will replace the response body with a standard error object \{ message: "..." \}, ignoring any data passed to ctx.send().

MethodStatus CodeDescription
.badRequest(msg?)400Client side error. If msg is provided, returns \{ message, data \}.
.unauthorized(msg?)401Returns `{ message: msg
.forbidden(msg?)403Returns `{ message: msg
.notFound(msg?)404Returns `{ message: msg
.conflict(msg?)409Resource conflict. If msg is provided, returns \{ message, data \}.
.unprocessable(errs?, msg?)422Returns `{ message, errors: errs
.tooManyRequests(msg?)429Returns `{ message: msg
MethodStatus CodeDescription
.error(msg?)500Returns \{ message: msg || 'Internal Server Error' \}.
MethodStatus CodeDescription
.notModified()304Resource not modified (caching).
MethodDescription
.build(status)Finalize the response with any specific HTTP status code.

export default (ctx) => {
return ctx.send({
success: true,
message: 'User updated successfully'
}).ok();
}
export default async (ctx) => {
const body = await ctx.json();
if (!body.username) {
return ctx.send({
username: ['Username is required']
}).unprocessable(null, 'Validation Failed');
}
// ... logic
}
export default (ctx) => {
return ctx.send('<h1>Welcome to GamanJS v2</h1>').ok();
}

Cookies are also managed via the context:

export default (ctx) => {
ctx.cookies.set('session', 'abc-123', { httpOnly: true });
return ctx.send({ message: 'Cookie set' }).ok();
}

ta`.