Hono: File Upload, WebSocket, dan Deployment
Fitur lanjut untuk aplikasi production-ready
Tujuan Pembelajaran
- Bisa handle file upload di Hono
- Mengerti WebSocket dengan Hono
- Bisa deploy Hono ke berbagai platform
Analogi
Hono Features:
├── File upload (multipart/form-data)
├── WebSocket (real-time)
├── Streaming response
├── JSX response (SSR)
└── Edge runtime support
Hono support fitur modern yang dibutuhkan aplikasi production
Penjelasan Konsep
Setelah menguasai routing, middleware, dan validasi, saatnya mengeksplor fitur lanjut Hono yang sering dibutuhkan di aplikasi nyata.
File Upload
Hono bisa menangani file upload melalui multipart/form-data.
Data form bisa diakses melalui c.req.parseBody().
app.post('/upload', async (c) => {
const body = await c.req.parseBody();
const file = body.file as File; // File object (web standard)
// Simpan file
await Bun.write(`./uploads/${file.name}`,
File);
return c.json({
filename: file.name,
size: file.size,
type: file.type,
});
});
WebSocket dengan Hono
Hono support WebSocket melalui adapter.
Di Bun:
import { createBunWebSocket } from 'hono/bun';
const { upgradeWebSocket, websocket } = createBunWebSocket();
app.get('/ws', upgradeWebSocket((c) => ({
onOpen(ws) {
ws.send('Connected!');
},
onMessage(ws, message) {
ws.send(`Echo: ${message}`);
},
onClose() {
console.log('Client disconnected');
},
})));
Bun.serve({
fetch: app.fetch,
websocket,
});
Streaming Response
Hono support streaming untuk response besar atau real-time data:
app.get('/stream',
(c) => {
return new Response(
new ReadableStream({
async start(controller) {
for (let i = 0; i < 10; i++) {
controller.enqueue(`data: ${i}
`);
await new Promise(r => setTimeout(r, 1000));
}
controller.close();
},
}),
{ headers: { 'Content-Type': 'text/event-stream' } }
);
});
Deployment Options
Hono bisa di-deploy ke banyak platform:
- Bun runtime: Bun.serve({ fetch: app.fetch })
- Node.js: export default app (untuk serverless)
- Cloudflare Workers: export default app (native support)
- Vercel Edge: export default app (edge runtime)
- Deno: Deno.serve(app.fetch)
Cloudflare Workers Example
// wrangler.toml
// [env.production]
// routes = [{ pattern = "api.example.com/*",
Custom_domain = true }]
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Hello from the Edge!'));
export default app; // That's it!
Notice: Tidak perlu listen pada port!
Cloudflare Workers menggunakan fetch handler directly.
Contoh Kode
// File upload + Bun integration
import { Hono } from 'hono';
const app = new Hono();
// Single file upload
app.post('/upload', async (c) => {
const body = await c.req.parseBody();
const file = body.file as File;
if (!file) return c.json({ error: 'No file' }, 400);
// Validate file type
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
if (!allowedTypes.includes(file.type)) {
return c.json({ error: 'Invalid file type' }, 400);
}
// Validate file size (max 5MB)
if (file.size > 5 * 1024 * 1024) {
return c.json({ error: 'File too large (max 5MB)' }, 400);
}
// Generate unique filename
const ext = file.name.split('.').pop();
const filename = `${Date.now()}-${Math.random().toString(36).slice(2)}.${ext}`;
// Save with Bun
await Bun.write(`./uploads/${filename}`, file);
return c.json({
filename,
originalName: file.name,
size: file.size,
url: `/uploads/${filename}`,
}, 201);
});
// Serve uploaded files
app.get('/uploads/:filename', async (c) => {
const filename = c.req.param('filename');
const file = Bun.file(`./uploads/${filename}`);
if (!(await file.exists())) {
return c.json({ error: 'File not found' }, 404);
}
return new Response(file);
});
export default app;Penjelasan Kode
Prompt AI
Tambahkan resize gambar menggunakan library sharp setelah upload. Simpan versi thumbnail dan original.
Pertanyaan Reflektif
Deploy Hono app-mu ke Cloudflare Workers atau platform edge lainnya. Rasakan performa edge computing!