ADR-006: Hono Framework for Edge API
Status: Accepted
Date: 2026-02-01
Deciders: Abdisamed Mohamed
Related ADRs: ADR-002 (Edge-First Architecture)
Context
CepatEdge requires a lightweight, fast API framework optimized for Cloudflare Workers. The framework must support:
- TypeScript first-class
- Middleware system
- Routing with parameters
- Request/response handling
- Error handling
- Performance optimization
- Small bundle size
- Edge runtime compatibility
Traditional Node.js frameworks (Express, Fastify, Koa) are too heavy for edge environments and include unnecessary features.
Decision
Use Hono framework for the CepatEdge API layer.
Implementation
Core Architecture
typescript
import { Hono } from 'hono';
// Type-safe Hono app with environment
type Env = {
CEPATEDGE_CACHE: DurableObjectNamespace;
DATABASE_URL: string;
JWT_SECRET: string;
};
const app = new Hono<{ Bindings: Env }>();
// Middleware
app.use('*', cors());
app.use('/api/*', authMiddleware);
// Routes
app.get('/api/health', (c) => c.json({ status: 'ok' }));
app.get('/api/maintenance', async (c) => {
const user = c.get('user');
const params = c.req.query();
// Business logic here
return c.json({ data: [] });
});
// Error handling
app.onError((err, c) => {
console.error(err);
return c.json({ error: 'Internal server error' }, 500);
});
export default app;Middleware System
typescript
// Authentication middleware
const authMiddleware: MiddlewareHandler = async (c, next) => {
const token = c.req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return c.json({ error: 'Unauthorized' }, 401);
}
const user = await authenticateUser(token, c.env);
c.set('user', user);
await next();
};
// Role-based authorization
const roleMiddleware = (roles: string[]): MiddlewareHandler => {
return async (c, next) => {
const user = c.get('user');
if (!user || !roles.includes(user.role)) {
return c.json({ error: 'Forbidden' }, 403);
}
await next();
};
};
// Usage in routes
app.get('/api/admin/users', roleMiddleware(['admin']), async (c) => {
// Admin-only logic
});Performance Optimizations
typescript
// Response caching
app.get('/api/public/data', cacheMiddleware(300), async (c) => {
// Cached for 5 minutes
});
// Streaming responses
app.get('/api/reports/export', async (c) => {
const stream = generateReportStream();
return new Response(stream, {
headers: { 'Content-Type': 'application/octet-stream' }
});
});Consequences
Positive
- Edge Optimized: Built specifically for Cloudflare Workers
- TypeScript First: Comprehensive type safety
- Lightweight: Minimal bundle size (<50KB)
- Fast: Optimized for edge performance
- Middleware System: Flexible request processing
- Developer Experience: Intuitive API, excellent documentation
Negative
- Learning Curve: New framework for team members
- Ecosystem: Smaller community than Express/Fastify
- Edge-Specific: Not suitable for traditional server environments
- Limited Features: Focused scope, fewer built-in features
Mitigation
- Documentation: Comprehensive guides and examples
- Migration Path: Clear migration strategy from existing APIs
- Testing: Built-in testing utilities and patterns
- Community: Growing ecosystem with good support
Performance Benchmarks
Bundle Size
- Core Framework: ~15KB gzipped
- With Middleware: ~25KB gzipped
- Full Application: ~45KB gzipped
Response Times
- Simple Routes: <5ms
- Database Routes: <50ms (with caching)
- Complex Logic: <100ms
- Error Handling: <10ms
Memory Usage
- Base Application: <10MB
- With Caching: <25MB
- Peak Load: <50MB
Alternatives Considered
Express.js
- Pros: Mature, large ecosystem, familiar API
- Cons: Heavy bundle size, not edge-optimized, Node.js specific
Fastify
- Pros: High performance, plugin ecosystem, validation
- Cons: Bundle size, learning curve, not edge-native
Workers Native API
- Pros: Direct Workers API, maximum performance
- Cons: Verbose, error-prone, no structure
SvelteKit API Routes
- Pros: Framework integration, file-based routing
- Cons: Additional complexity, not edge-focused
Developer Experience
Type Safety
typescript
// Full type inference
app.get('/api/users/:id', async (c) => {
const id = c.req.param('id'); // Typed as string
const user = await getUser(id); // Return type inferred
return c.json(user); // Response type checked
});Middleware Composition
typescript
// Composable middleware
const apiMiddleware = compose([
cors(),
rateLimit(),
auth(),
logging()
]);
app.use('/api/*', apiMiddleware);Error Handling
typescript
// Centralized error handling
app.onError((err, c) => {
// Log error with context
console.error({
error: err.message,
path: c.req.path,
user: c.get('user')?.id,
timestamp: Date.now()
});
// Return appropriate error response
if (err instanceof ValidationError) {
return c.json({ error: 'Validation failed' }, 400);
}
return c.json({ error: 'Internal server error' }, 500);
});Testing Support
Built-in Testing Utilities
typescript
import { testClient } from 'hono/testing';
describe('API Routes', () => {
const client = testClient(app);
it('should return health status', async () => {
const res = await client.api.health.$get();
expect(res.status).toBe(200);
});
});References
- Hono Framework Documentation
- Cloudflare Workers Runtime APIs
- CepatEdge Performance Benchmarks
- Edge Computing Best Practices