refactor: migrate API routes to Hono sub-router
- Create Hono router in api.ts
- Convert 6 API endpoints to Hono format:
- GET /api/deposit/balance
- POST /api/deposit/deduct
- POST /api/test
- POST /api/chat
- POST /api/contact
- GET /api/metrics
- Use Hono CORS middleware for /contact
- Remove manual handleApiRequest and handleContactPreflight
- Integrate with main app via app.route('/api', apiRouter)
Benefits:
- Cleaner declarative routing (44 insertions, 48 deletions)
- Built-in CORS middleware
- Better code organization
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Env, EmailMessage, ProvisionMessage, MessageBatch } from './types';
|
import { Env, EmailMessage, ProvisionMessage, MessageBatch } from './types';
|
||||||
import { sendMessage, setWebhook, getWebhookInfo } from './telegram';
|
import { sendMessage, setWebhook, getWebhookInfo } from './telegram';
|
||||||
import { handleWebhook } from './routes/webhook';
|
import { handleWebhook } from './routes/webhook';
|
||||||
import { handleApiRequest } from './routes/api';
|
import { apiRouter } from './routes/api';
|
||||||
import { handleHealthCheck } from './routes/health';
|
import { handleHealthCheck } from './routes/health';
|
||||||
import { parseBankSMS } from './services/bank-sms-parser';
|
import { parseBankSMS } from './services/bank-sms-parser';
|
||||||
import { matchPendingDeposit } from './services/deposit-matcher';
|
import { matchPendingDeposit } from './services/deposit-matcher';
|
||||||
@@ -69,8 +69,8 @@ app.get('/webhook-info', async (c) => {
|
|||||||
return c.json(result);
|
return c.json(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
// API routes
|
// API routes - use Hono router
|
||||||
app.all('/api/*', (c) => handleApiRequest(c.req.raw, c.env, new URL(c.req.url)));
|
app.route('/api', apiRouter);
|
||||||
|
|
||||||
// Telegram Webhook
|
// Telegram Webhook
|
||||||
app.post('/webhook', (c) => handleWebhook(c.req.raw, c.env));
|
app.post('/webhook', (c) => handleWebhook(c.req.raw, c.env));
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import { cors } from 'hono/cors';
|
||||||
import { Env } from '../types';
|
import { Env } from '../types';
|
||||||
import { sendMessage } from '../telegram';
|
import { sendMessage } from '../telegram';
|
||||||
import {
|
import {
|
||||||
@@ -762,18 +764,6 @@ async function handleContactForm(request: Request, env: Env): Promise<Response>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* OPTIONS /api/contact - CORS preflight for contact API
|
|
||||||
*
|
|
||||||
* @param env - Environment bindings
|
|
||||||
* @returns Response with CORS headers
|
|
||||||
*/
|
|
||||||
async function handleContactPreflight(env: Env): Promise<Response> {
|
|
||||||
return new Response(null, {
|
|
||||||
headers: getCorsHeaders(env),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /api/metrics - Circuit Breaker 상태 조회 (관리자 전용)
|
* GET /api/metrics - Circuit Breaker 상태 조회 (관리자 전용)
|
||||||
*
|
*
|
||||||
@@ -837,7 +827,7 @@ async function handleMetrics(request: Request, env: Env): Promise<Response> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 엔드포인트 처리 (라우터)
|
* API Router (Hono)
|
||||||
*
|
*
|
||||||
* Manual Test:
|
* Manual Test:
|
||||||
* 1. wrangler dev
|
* 1. wrangler dev
|
||||||
@@ -867,41 +857,47 @@ async function handleMetrics(request: Request, env: Env): Promise<Response> {
|
|||||||
* curl http://localhost:8787/api/metrics \
|
* curl http://localhost:8787/api/metrics \
|
||||||
* -H "Authorization: Bearer your-webhook-secret"
|
* -H "Authorization: Bearer your-webhook-secret"
|
||||||
*/
|
*/
|
||||||
export async function handleApiRequest(request: Request, env: Env, url: URL): Promise<Response> {
|
const api = new Hono<{ Bindings: Env }>();
|
||||||
// Deposit API - 잔액 조회 (namecheap-api 전용)
|
|
||||||
if (url.pathname === '/api/deposit/balance' && request.method === 'GET') {
|
|
||||||
return handleDepositBalance(request, env, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deposit API - 잔액 차감 (namecheap-api 전용)
|
// CORS middleware for /contact endpoint
|
||||||
if (url.pathname === '/api/deposit/deduct' && request.method === 'POST') {
|
api.use('/contact', cors({
|
||||||
return handleDepositDeduct(request, env);
|
origin: (origin, c) => {
|
||||||
}
|
const allowedOrigin = c.env.HOSTING_SITE_URL || 'https://hosting.anvil.it.com';
|
||||||
|
return origin === allowedOrigin ? origin : null;
|
||||||
|
},
|
||||||
|
allowMethods: ['POST', 'OPTIONS'],
|
||||||
|
allowHeaders: ['Content-Type'],
|
||||||
|
}));
|
||||||
|
|
||||||
// 테스트 API - 메시지 처리 후 응답 직접 반환
|
// GET /deposit/balance - 잔액 조회 (namecheap-api 전용)
|
||||||
if (url.pathname === '/api/test' && request.method === 'POST') {
|
api.get('/deposit/balance', async (c) => {
|
||||||
return handleTestApi(request, env);
|
const url = new URL(c.req.url);
|
||||||
}
|
return await handleDepositBalance(c.req.raw, c.env, url);
|
||||||
|
});
|
||||||
|
|
||||||
// Chat API - 인증된 채팅 API (프로덕션 활성화)
|
// POST /deposit/deduct - 잔액 차감 (namecheap-api 전용)
|
||||||
if (url.pathname === '/api/chat' && request.method === 'POST') {
|
api.post('/deposit/deduct', async (c) => {
|
||||||
return handleChatApi(request, env);
|
return await handleDepositDeduct(c.req.raw, c.env);
|
||||||
}
|
});
|
||||||
|
|
||||||
// 문의 폼 API (웹사이트용)
|
// POST /test - 테스트 API (개발 환경 전용)
|
||||||
if (url.pathname === '/api/contact' && request.method === 'POST') {
|
api.post('/test', async (c) => {
|
||||||
return handleContactForm(request, env);
|
return await handleTestApi(c.req.raw, c.env);
|
||||||
}
|
});
|
||||||
|
|
||||||
// CORS preflight for contact API
|
// POST /chat - 인증된 채팅 API (프로덕션)
|
||||||
if (url.pathname === '/api/contact' && request.method === 'OPTIONS') {
|
api.post('/chat', async (c) => {
|
||||||
return handleContactPreflight(env);
|
return await handleChatApi(c.req.raw, c.env);
|
||||||
}
|
});
|
||||||
|
|
||||||
// Metrics API - Circuit Breaker 상태 조회 (관리자 전용)
|
// POST /contact - 문의 폼 API (웹사이트용)
|
||||||
if (url.pathname === '/api/metrics' && request.method === 'GET') {
|
api.post('/contact', async (c) => {
|
||||||
return handleMetrics(request, env);
|
return await handleContactForm(c.req.raw, c.env);
|
||||||
}
|
});
|
||||||
|
|
||||||
return new Response('Not Found', { status: 404 });
|
// GET /metrics - Circuit Breaker 상태 조회 (관리자 전용)
|
||||||
}
|
api.get('/metrics', async (c) => {
|
||||||
|
return await handleMetrics(c.req.raw, c.env);
|
||||||
|
});
|
||||||
|
|
||||||
|
export { api as apiRouter };
|
||||||
|
|||||||
Reference in New Issue
Block a user