Menu
Zurück zum Blog
1 min read
Web Development

Hono: Das ultraschnelle Edge-Framework

Hono Framework für Edge Computing. Web Standards, Multi-Runtime Support und nur 12KB. Von Cloudflare Workers bis Bun.

HonoEdge FrameworkCloudflare WorkersWeb StandardsBunDeno
Hono: Das ultraschnelle Edge-Framework

Hono: Das ultraschnelle Edge-Framework

Meta-Description: Hono Framework für Edge Computing. Web Standards, Multi-Runtime Support und nur 12KB. Von Cloudflare Workers bis Bun.

Keywords: Hono, Edge Framework, Cloudflare Workers, Web Standards, Bun, Deno, Serverless Framework, TypeScript API


Einführung

Hono (炎 = Flamme) ist ein ultraschnelles Web-Framework gebaut auf Web Standards. Mit unter 12KB läuft es auf jedem JavaScript-Runtime: Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda und mehr.


Hono Overview

┌─────────────────────────────────────────────────────────────┐
│                      HONO FRAMEWORK                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Core Features:                                             │
│  ├── Web Standards API (Request/Response)                  │
│  ├── Zero Dependencies                                     │
│  ├── TypeScript First                                      │
│  └── < 12KB (hono/tiny)                                    │
│                                                             │
│  Supported Runtimes:                                        │
│  ├── Cloudflare Workers / Pages                            │
│  ├── Deno / Deno Deploy                                    │
│  ├── Bun                                                   │
│  ├── Node.js                                               │
│  ├── AWS Lambda                                            │
│  ├── Vercel Edge                                           │
│  ├── Fastly Compute                                        │
│  └── Netlify Edge                                          │
│                                                             │
│  Built-in Middleware:                                       │
│  ├── CORS, CSRF, ETag                                      │
│  ├── JWT, Basic Auth, Bearer Auth                          │
│  ├── Logger, Pretty JSON                                   │
│  ├── Compress, Cache                                       │
│  └── Streaming, SSE                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Quick Start

# Neues Projekt
npm create hono@latest my-app

# Runtime wählen:
# - cloudflare-workers
# - cloudflare-pages
# - deno
# - bun
# - nodejs
# - vercel

cd my-app
npm install
npm run dev

Basic Routing

// src/index.ts
import { Hono } from 'hono';

const app = new Hono();

// Basic Routes
app.get('/', (c) => c.text('Hello Hono!'));

app.get('/json', (c) => {
  return c.json({ message: 'Hello', timestamp: Date.now() });
});

// Path Parameters
app.get('/users/:id', (c) => {
  const id = c.req.param('id');
  return c.json({ userId: id });
});

// Query Parameters
app.get('/search', (c) => {
  const query = c.req.query('q');
  const page = c.req.query('page') || '1';
  return c.json({ query, page: parseInt(page) });
});

// POST mit Body
app.post('/users', async (c) => {
  const body = await c.req.json();
  return c.json({ created: body }, 201);
});

// Wildcards
app.get('/files/*', (c) => {
  const path = c.req.path;
  return c.text(`File path: ${path}`);
});

export default app;

Typed Routes mit RPC

// src/index.ts
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

const app = new Hono();

// Schema Definition
const createUserSchema = z.object({
  name: z.string().min(2),
  email: z.string().email()
});

const userParamsSchema = z.object({
  id: z.string().uuid()
});

// Typed Route
const route = app
  .get('/users', (c) => {
    return c.json([
      { id: '1', name: 'Alice' },
      { id: '2', name: 'Bob' }
    ]);
  })
  .post(
    '/users',
    zValidator('json', createUserSchema),
    (c) => {
      const data = c.req.valid('json');
      // data ist typisiert: { name: string; email: string }
      return c.json({ id: crypto.randomUUID(), ...data }, 201);
    }
  )
  .get(
    '/users/:id',
    zValidator('param', userParamsSchema),
    (c) => {
      const { id } = c.req.valid('param');
      return c.json({ id, name: 'Alice' });
    }
  );

// Type Export für Client
export type AppType = typeof route;

export default app;
// Client-Side (hc = Hono Client)
import { hc } from 'hono/client';
import type { AppType } from './server';

const client = hc<AppType>('http://localhost:8787');

// Vollständig typisiert!
const users = await client.users.$get();
const newUser = await client.users.$post({
  json: { name: 'Charlie', email: 'charlie@example.com' }
});

Middleware

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { jwt } from 'hono/jwt';
import { logger } from 'hono/logger';
import { prettyJSON } from 'hono/pretty-json';
import { secureHeaders } from 'hono/secure-headers';
import { compress } from 'hono/compress';

const app = new Hono();

// Global Middleware
app.use('*', logger());
app.use('*', secureHeaders());
app.use('*', compress());

// CORS für API Routes
app.use('/api/*', cors({
  origin: ['https://example.com', 'https://app.example.com'],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization'],
  credentials: true
}));

// JWT für geschützte Routes
app.use('/api/protected/*', jwt({
  secret: process.env.JWT_SECRET!
}));

// Pretty JSON in Development
if (process.env.NODE_ENV === 'development') {
  app.use('*', prettyJSON());
}

// Custom Middleware
const timing = () => {
  return async (c, next) => {
    const start = Date.now();
    await next();
    const duration = Date.now() - start;
    c.header('X-Response-Time', `${duration}ms`);
  };
};

app.use('*', timing());

// Protected Route
app.get('/api/protected/me', (c) => {
  const payload = c.get('jwtPayload');
  return c.json({ user: payload });
});

Error Handling

import { Hono } from 'hono';
import { HTTPException } from 'hono/http-exception';

const app = new Hono();

// Custom Error Handler
app.onError((err, c) => {
  if (err instanceof HTTPException) {
    return c.json(
      { error: err.message, status: err.status },
      err.status
    );
  }

  console.error(err);
  return c.json(
    { error: 'Internal Server Error', status: 500 },
    500
  );
});

// Not Found Handler
app.notFound((c) => {
  return c.json({ error: 'Not Found', status: 404 }, 404);
});

// Throwing Errors
app.get('/users/:id', async (c) => {
  const user = await getUser(c.req.param('id'));

  if (!user) {
    throw new HTTPException(404, { message: 'User not found' });
  }

  return c.json(user);
});

// Mit Custom Response
app.get('/admin', (c) => {
  const isAdmin = checkAdmin(c);

  if (!isAdmin) {
    throw new HTTPException(403, {
      message: 'Forbidden',
      res: c.json({ error: 'Admin access required' }, 403)
    });
  }

  return c.json({ admin: true });
});

Cloudflare Workers Integration

// src/index.ts
import { Hono } from 'hono';

type Bindings = {
  DB: D1Database;
  KV: KVNamespace;
  AI: Ai;
  BUCKET: R2Bucket;
};

const app = new Hono<{ Bindings: Bindings }>();

// D1 Database
app.get('/users', async (c) => {
  const { results } = await c.env.DB
    .prepare('SELECT * FROM users LIMIT 10')
    .all();
  return c.json(results);
});

// KV Storage
app.get('/cache/:key', async (c) => {
  const key = c.req.param('key');
  const value = await c.env.KV.get(key);

  if (!value) {
    return c.json({ error: 'Not found' }, 404);
  }

  return c.json({ key, value: JSON.parse(value) });
});

app.put('/cache/:key', async (c) => {
  const key = c.req.param('key');
  const body = await c.req.json();

  await c.env.KV.put(key, JSON.stringify(body), {
    expirationTtl: 3600 // 1 Stunde
  });

  return c.json({ success: true });
});

// R2 Storage
app.post('/upload', async (c) => {
  const formData = await c.req.formData();
  const file = formData.get('file') as File;

  await c.env.BUCKET.put(file.name, file);

  return c.json({ uploaded: file.name });
});

// Workers AI
app.post('/ai/chat', async (c) => {
  const { message } = await c.req.json();

  const response = await c.env.AI.run('@cf/meta/llama-2-7b-chat-int8', {
    messages: [{ role: 'user', content: message }]
  });

  return c.json(response);
});

export default app;

Streaming & SSE

import { Hono } from 'hono';
import { streamSSE, streamText } from 'hono/streaming';

const app = new Hono();

// Server-Sent Events
app.get('/sse', (c) => {
  return streamSSE(c, async (stream) => {
    let id = 0;

    while (true) {
      await stream.writeSSE({
        data: JSON.stringify({ time: new Date().toISOString() }),
        event: 'tick',
        id: String(id++)
      });

      await stream.sleep(1000);
    }
  });
});

// Text Streaming (für AI)
app.get('/stream', (c) => {
  return streamText(c, async (stream) => {
    const words = 'Hello, this is a streaming response!'.split(' ');

    for (const word of words) {
      await stream.write(word + ' ');
      await stream.sleep(100);
    }
  });
});

// AI Chat Streaming
app.post('/chat', async (c) => {
  const { message } = await c.req.json();

  return streamText(c, async (stream) => {
    const response = await openai.chat.completions.create({
      model: 'gpt-4',
      messages: [{ role: 'user', content: message }],
      stream: true
    });

    for await (const chunk of response) {
      const content = chunk.choices[0]?.delta?.content;
      if (content) {
        await stream.write(content);
      }
    }
  });
});

HonoX (Meta-Framework)

// HonoX: File-based Routing + Islands Architecture

// app/routes/index.tsx
export default function Home() {
  return (
    <html>
      <body>
        <h1>Welcome to HonoX</h1>
        <Counter /> {/* Client Island */}
      </body>
    </html>
  );
}

// app/routes/api/users.ts
import { Hono } from 'hono';

const app = new Hono();

app.get('/', (c) => c.json({ users: [] }));

export default app;

Fazit

Hono bietet:

  1. Ultra-Lightweight: < 12KB, zero dependencies
  2. Multi-Runtime: Gleicher Code überall
  3. Web Standards: Request/Response API
  4. Type-Safe RPC: End-to-End TypeScript

Das ideale Framework für Edge-First Entwicklung.


Bildprompts

  1. "Flame icon transforming into web API endpoints, Hono framework concept"
  2. "Code running across multiple cloud platforms, multi-runtime visualization"
  3. "Lightweight feather compared to heavy framework boxes, minimal bundle"

Quellen