Skip to content

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