Hono Integration
Build powerful APIs with Hono in Bini.js - file-based routing, middleware, and type safety.
File-Based API Routing
Hono is a fast, lightweight web framework that works everywhere. Bini.js integrates Hono with file-based API routing - your file structure defines your API routes.
Your API route is determined by the file path inside src/app/api/. The file name becomes the route segment:
| File Path | API Route |
|---|---|
| src/app/api/hello.ts | /api/hello |
| src/app/api/user.ts | /api/user |
| src/app/api/posts.ts | /api/posts |
| src/app/api/posts/[id].ts | /api/posts/:id |
| src/app/api/[...catch].ts | /api/* |
/api prefix - bini-router strips it in dev/preview and mounts the app under /api in production.Basic Hono App
Create a Hono app in src/app/api/ and default export it:
// src/app/api/hello.ts -> /api/hello
import { Hono } from 'hono'
const app = new Hono()
app.all('/hello', (c) => {
return c.json({
message: 'Hello from Bini.js!',
timestamp: new Date().toISOString(),
method: c.req.method,
})
})
export default appRouting with Hono
Hono provides a powerful routing system with path parameters, query parameters, and more:
// src/app/api/users.ts -> /api/users
import { Hono } from 'hono'
const app = new Hono()
app.get('/users', (c) => c.json({ users: ['alice', 'bob'] }))
app.get('/users/:id', (c) => c.json({ id: c.req.param('id') }))
app.post('/users', async (c) => c.json({ created: await c.req.json() }, 201))
app.put('/users/:id', async (c) =>
c.json({ id: c.req.param('id'), ...(await c.req.json()) })
)
app.delete('/users/:id', (c) =>
c.json({ message: `Deleted ${c.req.param('id')}` })
)
export default app| Method | Route Pattern | Full URL |
|---|---|---|
| GET | /users | /api/users |
| GET | /users/:id | /api/users/123 |
| POST | /users | /api/users |
| PUT | /users/:id | /api/users/123 |
| DELETE | /users/:id | /api/users/123 |
Dynamic API Routes
Use [param] in filenames for dynamic segments:
// src/app/api/posts/[id].ts -> /api/posts/:id
import { Hono } from 'hono'
const app = new Hono()
app.get('/posts/:id', (c) => c.json({ id: c.req.param('id') }))
export default app// src/app/api/[...catch].ts -> /api/*
import { Hono } from 'hono'
const app = new Hono()
app.all('*', (c) => c.json({ path: c.req.path }))
export default appMiddleware
Hono has built-in middleware for common tasks:
// src/app/api/secure.ts -> /api/secure
import { Hono } from 'hono'
import { cors, logger, jwt, timeout } from 'hono/middleware'
const app = new Hono()
app.use('*', cors())
app.use('*', logger())
app.use('*', timeout(5000))
app.get('/secure', (c) => c.json({ message: 'Public' }))
export default app| Middleware | Purpose |
|---|---|
| cors | Cross-Origin Resource Sharing |
| logger | Request logging |
| jwt | JWT authentication |
| timeout | Request timeout |
| prettyJSON | Pretty JSON responses |
Request Handling
Hono provides convenient methods for accessing request data:
// src/app/api/echo.ts -> /api/echo
import { Hono } from 'hono'
const app = new Hono()
app.all('/echo', async (c) => {
const params = c.req.param()
const query = c.req.query()
const page = c.req.query('page')
const userAgent = c.req.header('User-Agent')
const body = await c.req.json().catch(() => null)
return c.json({
method: c.req.method,
path: c.req.path,
params,
query: { page, ...query },
headers: { userAgent },
body,
})
})
export default appResponse Handling
Hono provides flexible response methods:
// src/app/api/responses.ts -> /api/responses
import { Hono } from 'hono'
const app = new Hono()
app.get('/json', (c) => c.json({ message: 'Hello' }))
app.get('/text', (c) => c.text('Hello Text'))
app.get('/html', (c) => c.html('<h1>Hello</h1>'))
app.get('/redirect', (c) => c.redirect('https://example.com', 302))
app.post('/created', (c) => c.json({ message: 'Created' }, 201))
app.get('/error', (c) => c.json({ error: 'Error' }, 500))
export default appValidation
Validate incoming requests with Zod:
// src/app/api/posts.ts -> /api/posts
import { Hono } from 'hono'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
const app = new Hono()
const postSchema = z.object({
title: z.string().min(1).max(100),
content: z.string().min(1),
})
app.post('/posts', zValidator('json', postSchema), async (c) => {
const body = c.req.valid('json')
return c.json({ post: { id: Date.now(), ...body } }, 201)
})
export default appzod and @hono/zod-validator for request validation with TypeScript inference.Environment Variables
Use getEnv() and requireEnv() from bini-env:
// src/app/api/config.ts -> /api/config
import { Hono } from 'hono'
import { getEnv, requireEnv } from 'bini-env'
const app = new Hono()
app.get('/config', (c) => {
const ctx = c as any
const apiKey = requireEnv(ctx, 'MY_API_KEY')
const appName = getEnv(ctx, 'APP_NAME') ?? 'Bini.js'
return c.json({ appName, hasApiKey: !!apiKey })
})
export default appc once at the top of your handler with const ctx = c as any. Then use requireEnv(ctx, 'KEY') for required vars and getEnv(ctx, 'KEY') ?? 'default' for optional ones.Error Handling
Handle errors gracefully with Hono's error handling:
// src/app/api/robust.ts -> /api/robust
import { Hono } from 'hono'
import { getEnv } from 'bini-env'
const app = new Hono()
app.onError((err, c) => {
const isDev = getEnv(c as any, 'NODE_ENV') === 'development'
return c.json(
{
error: 'Internal Server Error',
...(isDev && { details: err.message }),
},
500
)
})
app.notFound((c) => c.json({ error: 'Not Found' }, 404))
app.get('/robust/users/:id', (c) => {
const id = c.req.param('id')
if (id === 'admin') {
return c.json({ error: 'Access denied' }, 403)
}
return c.json({ id, name: 'John' })
})
export default appNested Routes
Organize complex APIs with nested sub-routers:
// src/app/api/index.ts -> /api
import { Hono } from 'hono'
const app = new Hono()
const users = new Hono()
.get('/users', (c) => c.json({ users: [] }))
.get('/users/:id', (c) => c.json({ id: c.req.param('id') }))
const posts = new Hono()
.get('/posts', (c) => c.json({ posts: [] }))
.get('/posts/:id', (c) => c.json({ id: c.req.param('id') }))
app.route('/', users)
app.route('/', posts)
export default appWhen to Use Hono
| Scenario | Recommendation |
|---|---|
| Multiple endpoints in one file | Hono - Recommended |
| Need middleware (CORS, auth, logging) | Hono - Recommended |
| Complex routing patterns | Hono - Recommended |
| Production APIs with many routes | Hono - Recommended |
| Single endpoint with simple logic | Plain handler |
| Quick prototypes | Plain handler |