Response Helpers
ubean API routes use Hono under the hood, so response helpers come from Hono’s context object (c). ubean does not export standalone json(), html(), text(), redirect(), setHeader(), createError(), send(), stream(), download(), noContent(), notFound(), etc. — use Hono’s context methods instead.
JSON Response
// src/routes/api/hello.ts
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
return c.json({ message: 'Hello' });
});
// With status code
export const POST = defineHandler(c => {
return c.json({ created: true }, 201);
});
// With headers
export const PUT = defineHandler(c => {
return c.json(
{ updated: true },
200,
{ 'X-Custom-Header': 'value' }
);
});HTML Response
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
return c.html('<h1>Hello</h1>');
});
// With status
export const GET_ERROR = defineHandler(c => {
return c.html('<h1>Not Found</h1>', 404);
});Plain Text Response
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
return c.text('Hello World');
});Redirect
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
// 302 redirect (default)
return c.redirect('/new-url');
});
// Permanent redirect (301)
export const GET_PERMANENT = defineHandler(c => {
return c.redirect('/new-url', 301);
});Setting Headers
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
c.header('Cache-Control', 'max-age=3600');
c.header('X-Custom', 'value');
return c.json({ ok: true });
});Append vs set:
c.header('Set-Cookie', 'session=abc; Path=/'); // Overwrites
c.header('Set-Cookie', 'tracking=xyz; Path=/', { append: true }); // AppendsSetting Status Code
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
c.status(204);
return c.body(null);
});
// Or pass status to response methods
export const POST = defineHandler(c => {
return c.json({ created: true }, 201);
});No Content (204)
import { defineHandler } from 'ubean/server';
export const DELETE = defineHandler(c => {
// Delete resource...
c.status(204);
return c.body(null);
});Not Found (404)
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
const user = findUser();
if (!user) {
c.status(404);
return c.json({ error: 'Not found' });
}
return c.json({ user });
});Error Responses
Throw an error or return an error response:
import { defineHandler, defineHandlerMeta } from 'ubean/server';
export const GET = defineHandler(
defineHandlerMeta({ requiresAuth: true }),
c => {
const user = c.get('user');
if (!user) {
c.status(401);
return c.json({ error: 'Unauthorized' });
}
return c.json({ user });
}
);Throw HTTPException (from Hono):
import { defineHandler } from 'ubean/server';
import { HTTPException } from 'hono/http-exception';
export const GET = defineHandler(c => {
throw new HTTPException(404, { message: 'Resource not found' });
});Streaming Response (SSE)
import { defineHandler } from 'ubean/server';
import { streamSSE } from 'hono/streaming';
export const GET = defineHandler(c => {
return streamSSE(c, async stream => {
let id = 0;
const sendEvent = async () => {
await stream.writeSSE({ data: `Event ${id++}`, event: 'update' });
};
await sendEvent();
const interval = setInterval(sendEvent, 1000);
stream.onAbort(() => clearInterval(interval));
});
});Streaming Body
import { defineHandler } from 'ubean/server';
import { stream } from 'hono/streaming';
export const GET = defineHandler(c => {
return stream(c, async stream => {
await stream.writeln('Hello');
await stream.writeln('World');
});
});Cookies
import { defineHandler } from 'ubean/server';
export const POST = defineHandler(c => {
// Set cookie
c.header('Set-Cookie', 'session=abc; HttpOnly; Path=/; Max-Age=3600');
// Read cookie
const session = c.req.header('Cookie');
return c.json({ ok: true });
});Use hono/cookie for typed cookie helpers:
import { defineHandler } from 'ubean/server';
import { getCookie, setCookie } from 'hono/cookie';
export const GET = defineHandler(c => {
const session = getCookie(c, 'session');
return c.json({ session });
});
export const POST = defineHandler(c => {
setCookie(c, 'session', 'abc', {
httpOnly: true,
maxAge: 3600,
path: '/'
});
return c.json({ ok: true });
});File Download
import { defineHandler } from 'ubean/server';
export const GET = defineHandler(c => {
const buffer = readFileBytes();
c.header('Content-Disposition', 'attachment; filename="document.pdf"');
c.header('Content-Type', 'application/pdf');
return c.body(buffer);
});Best Practices
- Use Hono’s context methods:
c.json(),c.html(),c.text(),c.redirect(),c.header(),c.status() - Validate inputs: Use
validator()fromhono-openapifor type-safe requests - Document endpoints: Use
describeRoute()for OpenAPI metadata - Handle errors gracefully: Return appropriate status codes
- Set cache headers: Use
c.header('Cache-Control', ...)for static resources - Use streaming: For large responses or real-time data, use Hono’s streaming helpers