
ããªããšãªãããã«ãŠã§ã¢ã ã忥ããã Hono ã§åŠãã "å±€" ã®èãæ¹
ãèªèšŒ ã» ãã° ã» ãšã©ãŒåŠçã ãç©ã¿æšã ã«ããèšèšæèã
èªèšŒãã§ãã¯ããªã¯ãšã¹ããã°ããšã©ãŒãã³ããªã³ã°ã
ããªãã® API ãµãŒããŒã§ãããã㯠ã©ãã« æžãããŠããŸããïŒ
ããçãããã«ãŒããã³ãã©ã®äžã«ãå šéšããªãã
ãã®èšäºã¯ãããªãã®ããã«æžããŸããã
ããªããšãªãããã«ãŠã§ã¢ã ã®æ£äœ
ã¿ãªããã¯ããããªçµéšã¯ãããŸãããïŒ
ãExpress ã§ã Hono ã§ãã
ãããã«ãŠã§ã¢ã£ãŠ app.use( ) ã§è¿œå ãããã€ã§ããïŒã
äœ¿ãæ¹ã¯ç¥ã£ãŠããã
å
¬åŒããã¥ã¡ã³ãã®ãµã³ãã«ãåçµããã
CORS ã®ããã«ãŠã§ã¢ãå
¥ããã
Bearer èªèšŒã远å ããã
ã§ã ââ ãªããã®é çªãªã®ãã説æã§ããŸããïŒ
ããªããšãªããäžããé ã«æžããŠããã
ããªããšãªããåããŠãããã倧äžå€«ã
ããªããšãªããä»ã®ãããžã§ã¯ãããã³ããããã
ãã®ããªããšãªããããåãäœåºŠãèŠãããŸããã
ããæ¥ãèªèšŒããã«ãŠã§ã¢ã®åã«ãã°ããã«ãŠã§ã¢ã眮ããŠããããã§ã
èªèšŒå€±æã®ãªã¯ãšã¹ãããã°ã«æ®ããªãããšã«æ°ã¥ããŸããã
å¥ã®æ¥ã«ã¯ããšã©ãŒãã³ããªã³ã°ã®äœçœ®ãæªããŠã
ããã«ãŠã§ã¢å
ã§çºçããäŸå€ããã£ãããããã
ã¯ã©ã€ã¢ã³ãã«çã®ã¹ã¿ãã¯ãã¬ãŒã¹ãè¿ã£ãŠããã
ããªããšãªããã¯ããã€ãå¿ ãäºæ ã«ãªãã
ãã®èšäºã§ã¯ãåã Hono ã䜿ã£ãå人éçºã®ãªãã§èŸ¿ãçããã
ããã«ãŠã§ã¢ããç©ã¿æšããšããŠèšèšããèãæ¹ãå
±æããŸãã
ããã«ãŠã§ã¢ã¯ ãåŠçã ã§ã¯ãªã ãå±€ã
ãŸããçºæ³ã®è»¢æãå¿ èŠã§ãã
ããã«ãŠã§ã¢ããåŠçã®è¿œå ããšæããŠãããšã
ãããããããããšæ©èœãè©°ã蟌ã¿ãããªããŸãã
çµæãã²ãšã€ã®ããã«ãŠã§ã¢ãè¥å€§åããŠã
äœããã£ãŠããã®ãããããªããªãã
ããã«ãŠã§ã¢ã¯ãåŠçãã§ã¯ãªããå±€ãã§ãã
å°å±€ãæ³åããŠã¿ãŠãã ããã
äžçªäžã«å²©ç€ïŒãšã©ãŒãã³ããªã³ã°ïŒãããã
ãã®äžã«åå£ïŒãã°ïŒãç©ããã
ããã«ãã®äžã«è¡šåïŒèªèšŒïŒãããã
ãããŠå°è¡šïŒã«ãŒããã³ãã©ïŒã«æ€ç©ãçããã
ãªã¯ãšã¹ãã¯å°è¡šããå
¥ããå°å±€ãéã£ãŠå²©ç€ã«éããã
ã¬ã¹ãã³ã¹ã¯å²©ç€ããå°è¡šã«åãã£ãŠæ»ã£ãŠããã
ãã®ãäžããäžãžãäžããäžãžãã®æµããæèãããšã
ããã«ãŠã§ã¢ã® é çª ã«æå³ãçãŸããŸãã
Hono ã®ããã«ãŠã§ã¢ãããŸãã«ãã®æ§é ã§åããŸãã
app.use( ) ã§ç»é²ããé ã«ããªã¯ãšã¹ãã¯äžã®ããã«ãŠã§ã¢ãã
äžã®ããã«ãŠã§ã¢ãžæµããã¬ã¹ãã³ã¹ã¯éé ã«è¿ãã
Express ã䜿ã£ãããšãããæ¹ãªãã
ãã®æ§é èªäœã¯éŠŽæã¿ããããããããŸããã
ã§ããããªããã®é çªã«ããã®ãããèšèªåã§ããããšãšã
ããªããšãªãåããŠãããããšã«ã¯ã決å®çãªå·®ãããã®ã§ãã
ã«ãŒããã³ãã©ã«å šéšæŒã蟌ãã§ãã
ããªãŒã©ã³ã¹ãšããŠå人éçºãå§ããé ã
åã® API ã³ãŒãã¯ãããªææ§ã§ããã
app.get('/api/users/:id', async (c) => {
// ãã°åºå
console.log(`[${new Date().toISOString()}] GET /api/users/${c.req.param('id')}`)
// èªèšŒãã§ãã¯
const token = c.req.header('Authorization')?.replace('Bearer ', '')
if (!token) {
return c.json({ error: 'Unauthorized' }, 401)
}
const user = await verifyToken(token)
if (!user) {
return c.json({ error: 'Invalid token' }, 401)
}
// ããžãã¹ããžãã¯
try {
const targetUser = await db.user.findUnique({ where: { id: c.req.param('id') } })
if (!targetUser) {
return c.json({ error: 'Not found' }, 404)
}
return c.json(targetUser)
} catch (e) {
console.error(e)
return c.json({ error: 'Internal server error' }, 500)
}
})ãã°ãèªèšŒããšã©ãŒåŠçãããžãã¹ããžãã¯ã
å
šéšã 1 ã€ã®ãã³ãã©ã«åå±
ããŠããã
1 ã€ã®ãšã³ããã€ã³ããªãããŸã èªããŸãã
ã§ãããšã³ããã€ã³ãã 10 åã20 åãšå¢ãããã©ããªããã
åããã°åºåã³ãŒãã 20 ç®æã«ã³ãããããã
èªèšŒãã§ãã¯ã®ããžãã¯ã埮åŠã«éãããŒãžã§ã³ã 3 ã€ååšããã
ãšã©ãŒã¬ã¹ãã³ã¹ã®åœ¢åŒãçµ±äžãããŠããªãã
åã®ã³ãŒãããŒã¹ã¯ã3 ã¶æã§ãèªã¿ãããªãã³ãŒããã«ãªããŸããã
ãããåä»ãªã®ã¯ããåããŠãããããšã§ãã
ãã¹ãã¯éãã
API ã¯æ£åžžã«ã¬ã¹ãã³ã¹ãè¿ãã
ã§ããæ°ãããšã³ããã€ã³ãã远å ãããã³ã«ã
åããã€ã©ãŒãã¬ãŒããã³ããããæãæ¢ãŸãã
ãããã絶察ã«ã©ããã§ééãããªâŠã
ãã®äºæã¯ãçäžããŸããã
ãç©ã¿æšã ãšããæãæ¹
転æ©ã¯ãHono ã®å ¬åŒããã¥ã¡ã³ããèªã¿çŽããŠãããšãã§ããã
Hono ã®ããã«ãŠã§ã¢ã¯ãnext( ) ãåŒã¶ããšã§
ãæ¬¡ã®å±€ãã«åŠçãæž¡ããŸãã
next( ) ã®åã«æžããåŠçã¯ããªã¯ãšã¹ãæãã«ã
next( ) ã®åŸã«æžããåŠçã¯ãã¬ã¹ãã³ã¹æãã«å®è¡ãããã
app.use(async (c, next) => {
// â ãªã¯ãšã¹ãæã«ãããå®è¡ããã
await next()
// â ã¬ã¹ãã³ã¹æã«ãããå®è¡ããã
})ãã®ã·ã³ãã«ãªæ§é ãèŠãŠãåã¯ãããšããŸããã
ããã¯ãç©ã¿æšãã ã
1 ã€ã²ãšã€ã®ããã«ãŠã§ã¢ã¯ãç¬ç«ãããç©ã¿æšã®ãããã¯ãã
äžã«ç©ãé çªã§ãæ¯ãèããå€ããã
1 ã€æããŠããä»ã®ãããã¯ã¯åŽ©ããªãã
åã©ãã®é ãç©ã¿æšã§éãã èšæ¶ãèããŸããã
æåã«å€§ããªãããã¯ïŒåå°ïŒã眮ããŠã
ãã®äžã«å°ããªãããã¯ãéããŠããã
åå°ããã£ããããŠããã°ãäžã«äœãç©ãã§ãå®å®ããã
API ãµãŒããŒã®ããã«ãŠã§ã¢ããåãã ã£ãã®ã§ãã
åå°ïŒæäžå±€ïŒ:
ãšã©ãŒãã³ããªã³ã°
ðïž äœãèµ·ããŠããå¿
ãããã§åãæ¢ãã
äžéå±€:
ãã°
ðïž ãã¹ãŠã®ãªã¯ãšã¹ããšã¬ã¹ãã³ã¹ãèšé²ãã
äžå±€:
èªèšŒ
ðïž èš±å¯ããããªã¯ãšã¹ãã ããéã
ãã® 3 ã€ã®ç©ã¿æšãæ£ããé çªã§éããã°ã
ã«ãŒããã³ãã©ã«ã¯ ããžãã¹ããžãã¯ã ã ãæ®ãã
ä»¥åæžãããHono ã®ãšã©ãŒèšèšããã°ãšäŸå€ããæåã«ã決ããçç±ã
ã¯ãå®ã¯ãã®ç©ã¿æšã®ãåå°ãã«ãããéšåã§ããã
ãã®èšäºã§ã«ã¹ã¿ã äŸå€ã¯ã©ã¹ãš onError ãèšèšããããšã§ã
ä»åã®ãå±€ã®èãæ¹ããèŠããããã«ãªã£ãã®ã§ãã
ã3 ã€ã®ç©ã¿æšã åã®ããã«ãŠã§ã¢èšèšãã¿ãŒã³
å
·äœçã«ãåãã©ãããé çªã§
ããã«ãŠã§ã¢ãç©ãã§ãããããèŠãããŸãã
ãªã¯ãšã¹ã â
[1. ãšã©ãŒãã³ããªã³ã°å±€] â æäžå±€: äŸå€ãåãæ¢ãã
[2. ãã°å±€] â äžéå±€: ãªã¯ãšã¹ã / ã¬ã¹ãã³ã¹ãèšé²ãã
[3. èªèšŒå±€] â äžå±€: ã¢ã¯ã»ã¹ãå¶åŸ¡ãã
[ã«ãŒããã³ãã©] â ããžãã¹ããžãã¯ã ã
[3. èªèšŒå±€]
[2. ãã°å±€]
[1. ãšã©ãŒãã³ããªã³ã°å±€]
â ã¬ã¹ãã³ã¹ãªã¯ãšã¹ã㯠1 â 2 â 3 â ãã³ãã©ã®é ã«ééããŸãã
ã¬ã¹ãã³ã¹ã¯ãã³ãã© â 3 â 2 â 1 ã®é ã«æ»ããŸãã
ãã®é çªã«ã¯ãæç¢ºãªçç±ããããŸãã
ãªããšã©ãŒãã³ããªã³ã°ãæäžå±€ãªã®ã
ãšã©ãŒã¯ãã©ã®å±€ã§ãçºçãããããã§ãã
ãã°å±€ã§ãšã©ãŒãåºããããããªãã
èªèšŒå±€ã§æ³å®å€ã®äŸå€ãé£ã¶ãããããªãã
ã«ãŒããã³ãã©ã®ããžãã¹ããžãã¯ã§ DB æ¥ç¶ãåãããããããªãã
ã©ãã§äœãèµ·ããŠããæçµçã«ãšã©ãŒãã³ããªã³ã°å±€ãåãæ¢ããã
ããããæåŸã®ç Šãã§ãã
æäžå±€ã«çœ®ããããããä»ã®ãã¹ãŠã®å±€ãå®ããã®ã§ãã
ãªããã°ãäžéå±€ãªã®ã
ãã°ã¯ãèªèšŒã®æå / 倱æã«é¢ãããèšé²ãããããã§ãã
ãããã°å±€ãèªèšŒå±€ã®äžïŒåŸïŒã«ãã£ããã
èªèšŒã«å€±æãããªã¯ãšã¹ãã¯ãã°ã«æ®ããŸããã
äžæ£ã¢ã¯ã»ã¹ã®è©Šè¡ãæ€ç¥ã§ããªããªãã
éã«ããšã©ãŒãã³ããªã³ã°å±€ã®äžã«ãã°å±€ã眮ãããšã§ã
ãšã©ãŒãçºçãããªã¯ãšã¹ãã®æ
å ±ããã°ã«æ®ããŸãã
ãªãèªèšŒãæäžå±€ãªã®ã
èªèšŒã¯ãéããã匟ãããã®å€æã§ãã
匟ãããªã¯ãšã¹ãã¯ãããžãã¹ããžãã¯ã«å°éãããããªãã
æäžå±€ã«çœ®ãããšã§ãèªèšŒãééãããªã¯ãšã¹ãã ãã
ã«ãŒããã³ãã©ã«å±ããŸãã
ãã®ããªãããèšèªåã§ãããã©ãããã
ããªããšãªãããã«ãŠã§ã¢ããšãèšèšãããããã«ãŠã§ã¢ãã®
åããéãªã®ã§ãã
ãå®è£ ã Hono ã§ ã3 å±€ã®ç©ã¿æšã ãçµã¿ç«ãŠã
ããããã¯ãå®éã®ã³ãŒãã§ 3 ã€ã®ç©ã¿æšãçµã¿ç«ãŠãŸãã
åæãšããŠã以äžã®ç°å¢ãæ³å®ããŠããŸãã
â Hono v4 ç³»
â TypeScript
â Node.jsïŒCloudflare Workers ã§ãåæ§ã®æ§æãå¯èœïŒ
ãç©ã¿æš 1ã ãšã©ãŒãã³ããªã³ã°å±€ ïŒæäžå±€ïŒ
ãŸããåå°ãäœããŸãã
以åã®ãHono ã®ãšã©ãŒèšèšãã§ç޹ä»ããã«ã¹ã¿ã äŸå€ã¯ã©ã¹ã䜿ããŸãã
// middleware/error-handler.ts
import { Context } from 'hono'
import { AppException, InternalServerErrorException } from '../exceptions'
import { logger } from '../logger'
export const errorHandler = () => {
return async (c: Context, next: () => Promise<void>) => {
try {
await next()
} catch (err) {
const exception = err instanceof AppException
? err
: new InternalServerErrorException()
if (exception.statusCode >= 500) {
logger.error(exception.message, {
stack: err instanceof Error ? err.stack : undefined,
path: c.req.path,
method: c.req.method,
code: exception.code,
})
} else {
logger.warn(exception.message, {
path: c.req.path,
code: exception.code,
})
}
return c.json(
{
success: false,
error: { code: exception.code, message: exception.message },
},
exception.statusCode
)
}
}
}ãã€ã³ãã¯ãtry { await next( ) } catch (err) {} ãšããæ§é ã§ãã
next( ) ãåŒã¶ããšã§ã
äžã®å±€ïŒãã°å±€ãèªèšŒå±€ãã«ãŒããã³ãã©ïŒãã¹ãŠãå®è¡ãããŸãã
ãã®ã©ããã§äŸå€ãæãããããããã® catch ã§åãæ¢ããã
ãŸãã«ãæåŸã®ç Šãã§ãã
ãç©ã¿æš 2ã ãã°å±€ ïŒäžéå±€ïŒ
次ã«ããªã¯ãšã¹ããšã¬ã¹ãã³ã¹ãèšé²ãããã°å±€ãäœããŸãã
// middleware/request-logger.ts
import { Context } from 'hono'
import { logger } from '../logger'
export const requestLogger = () => {
return async (c: Context, next: () => Promise<void>) => {
const start = Date.now()
const method = c.req.method
const path = c.req.path
// ãªã¯ãšã¹ãæ: ãã°éå§
logger.info(`--> ${method} ${path}`, {
type: 'request',
method,
path,
userAgent: c.req.header('User-Agent'),
})
await next()
// ã¬ã¹ãã³ã¹æ: ãã°å®äºïŒæèŠæéãèšé²ïŒ
const duration = Date.now() - start
const status = c.res.status
logger.info(`<-- ${method} ${path} ${status} ${duration}ms`, {
type: 'response',
method,
path,
status,
duration,
})
}
}next( ) ã®ååŸã§åŠçãåããŠããã®ãèã§ãã
next( ) ã®å = ãªã¯ãšã¹ããå ¥ã£ãŠããç¬éãèšé²
next( ) ã®åŸ = ã¬ã¹ãã³ã¹ãè¿ãçŽåãèšé²ïŒæèŠæéã€ãïŒ
ããã§ããã¹ãŠã®ãªã¯ãšã¹ãã®ãå
¥ãããšãåºãã
æ§é åãã°ãšããŠæ®ããŸãã
èªèšŒã«å€±æãããªã¯ãšã¹ããããšã©ãŒãçºçãããªã¯ãšã¹ããããã¹ãŠã
ãç©ã¿æš 3ã èªèšŒå±€ ïŒäžå±€ïŒ
æåŸã«ãèªèšŒããã«ãŠã§ã¢ãäœããŸãã
// middleware/auth.ts
import { Context } from 'hono'
import { UnauthorizedException } from '../exceptions'
export const authGuard = () => {
return async (c: Context, next: () => Promise<void>) => {
const authHeader = c.req.header('Authorization')
if (!authHeader?.startsWith('Bearer ')) {
throw new UnauthorizedException(
'Authorization header is missing or invalid',
'AUTH_HEADER_MISSING'
)
}
const token = authHeader.replace('Bearer ', '')
const payload = await verifyToken(token) // JWT æ€èšŒãªã©
if (!payload) {
throw new UnauthorizedException(
'Token is invalid or expired',
'TOKEN_INVALID'
)
}
// æ€èšŒæžã¿ã®ãŠãŒã¶ãŒæ
å ±ãã³ã³ããã¹ãã«æ ŒçŽ
c.set('currentUser', payload)
await next()
}
}èªèšŒã«å€±æããå ŽåãUnauthorizedException ãæããã ãã§ãã
try-catch ã¯æžããŸããã
æããããäŸå€ã¯ã
äžã®å±€ïŒãšã©ãŒãã³ããªã³ã°å±€ïŒãåãæ¢ããŠãããŸãã
ãã°å±€ããªã¯ãšã¹ãæ
å ±ãèšé²ããŠãããŸãã
åå±€ã¯ãèªåã®è²¬åã ããæããã°ããã
ããããç©ã¿æšãã®åŒ·ãã§ãã
ãç©ã¿æšãéããã app.use( ) ã®é çª
3 ã€ã®ç©ã¿æšããHono ã®ã¢ããªã±ãŒã·ã§ã³ã«éããŸãã
// index.ts
import { Hono } from 'hono'
import { errorHandler } from './middleware/error-handler'
import { requestLogger } from './middleware/request-logger'
import { authGuard } from './middleware/auth'
import { NotFoundException } from './exceptions'
const app = new Hono()
// === ç©ã¿æšãéããïŒé çªãéèŠïŒïŒ ===
// 1. æäžå±€: ãšã©ãŒãã³ããªã³ã°ïŒãã¹ãŠã®äŸå€ãåãæ¢ããïŒ
app.use(errorHandler())
// 2. äžéå±€: ãã°ïŒãã¹ãŠã®ãªã¯ãšã¹ããèšé²ããïŒ
app.use(requestLogger())
// 3. äžå±€: èªèšŒïŒä¿è·ãããã«ãŒãã«ã®ã¿é©çšïŒ
app.use('/api/*', authGuard())
// === ã«ãŒããã³ãã©ïŒããžãã¹ããžãã¯ã ãïŒïŒ ===
app.get('/api/users/:id', async (c) => {
const id = c.req.param('id')
const currentUser = c.get('currentUser')
const user = await db.user.findUnique({ where: { id } })
if (!user) {
throw new NotFoundException('User not found', 'USER_NOT_FOUND')
}
return c.json({ success: true, data: user })
})
export default appã«ãŒããã³ãã©ãèŠãŠãã ããã
ãã°åºåã®ã³ãŒãããªãã
èªèšŒãã§ãã¯ã®ã³ãŒãããªãã
try-catch ããªãã
ããã®ã¯ãããžãã¹ããžãã¯ã ãã
ããŠãŒã¶ãŒãååŸããŠããªããã° 404 ãæãããããã°è¿ããã
ããã ãã§ãã
ãã°ã¯äžéå±€ãåæã«èšé²ããŠãããã
èªèšŒã¯äžå±€ãééæžã¿ïŒcurrentUser ã䜿ããïŒã
ãšã©ãŒã¯æäžå±€ãåãæ¢ããŠãããã
åå±€ãèªåã®ä»äºãããŠãããããã
ã«ãŒããã³ãã©ã¯ãããããããšãã ãã«éäžã§ããã®ã§ãã
ãç©ã¿æšã®è¶³ãåŒãã å±€ã®æè»æ§
ç©ã¿æšã®è¯ããšããã¯ãå·®ãæ¿ããå¹ãããšã§ãã
ããšãã°ãæ°ãããšã³ããã€ã³ãã°ã«ãŒãã远å ãããšãã
// 管çè
å°çšã«ãŒã: èªèšŒ + 管çè
æš©éãã§ãã¯
app.use('/admin/*', authGuard())
app.use('/admin/*', adminGuard()) // 远å ã®ç©ã¿æš
// å
¬é API: èªèšŒãªãïŒãã°ãšãšã©ãŒãã³ããªã³ã°ã ãïŒ
app.get('/public/health', (c) => c.json({ status: 'ok' }))å
¬é API ã«ã¯èªèšŒã®ç©ã¿æšãèŒããªãã
管çè
API ã«ã¯ãèªèšŒã®äžã«ããã«æš©éãã§ãã¯ã®ç©ã¿æšãèŒããã
ç©ã¿æšãè¶³ãã»åŒãã ãã§ãã«ãŒãããšã®æ¯ãèããå€ããã
ã«ãŒããã³ãã©ã®ã³ãŒãã¯äžå倿ŽããªããŠããã
ããããããã«ãŠã§ã¢ããå±€ããšããŠèšèšããæå€§ã®æ©æµã§ãã
ãæ°ããç©ã¿æšã®è¿œå äŸã ã¬ãŒããªããã
å°æ¥ãã¬ãŒããªãããïŒãªã¯ãšã¹ãå¶éïŒã
远å ããããªã£ããšããŸãããã
// ç©ã¿æšã 1 ã€è¿œå ããã ã
app.use(errorHandler())
app.use(requestLogger())
app.use(rateLimiter({ max: 100, window: '1m' })) // æ°ããç©ã¿æš
app.use('/api/*', authGuard())æ¢åã®ã³ãŒãã«åœ±é¿ãªãã
æ°ããç©ã¿æšããé©åãªäœçœ®ã«å·®ã蟌ãã ãã
ãã°å±€ã®äžãèªèšŒå±€ã®äžã«çœ®ãçç±ã¯æç¢ºã§ãã
ã¬ãŒããªãããã«åŒã£ããã£ããªã¯ãšã¹ãããã°ã«ã¯æ®ãããã
ã§ããèªèšŒããå
ã«ãã§ãã¯ããŠã
éå°ãªãªã¯ãšã¹ãã¯ããããèªèšŒåŠçã«é²ãŸããããªãã
é çªã®ããªãããèšèªåã§ãããããæ°ããç©ã¿æšã®çœ®ãå Žæãè¿·ããªãã
ãç©ã¿æšèšèšã®ã«ãŒã«ã 3 ã€ã®åå
æåŸã«ãåãããã«ãŠã§ã¢ãèšèšãããšãã«å®ã£ãŠãã 3 ã€ã®ååããŸãšããŸãã
ãåå 1ã 1 ã€ã®ç©ã¿æšã«ã 1 ã€ã®è²¬å
1 ã€ã®ããã«ãŠã§ã¢ããèªèšŒããã°ããšã©ãŒåŠçããããã®ã¯ NG ã§ãã
倪ã£ãããã«ãŠã§ã¢ã¯ããã¹ããé£ãããå·®ãæ¿ããå¹ããªããªããŸãã
1 ã€ã®ç©ã¿æš = 1 ã€ã®è²¬åã
è¿·ã£ããããã®ããã«ãŠã§ã¢ãäžæã§èª¬æã§ãããïŒã
ãšèªåããŠã¿ãŠãã ããã
äžæã§èª¬æã§ããªããªããåå²ã®ãµã€ã³ã§ãã
ãåå 2ã é çªã® ããªãã ãèšèªåãã
app.use( ) ã®äžŠã³é ããã³ã¡ã³ãã§èª¬æã§ããããã«ããŠããã
// 1. ãšã©ãŒãã³ããªã³ã°: ãã¹ãŠã®äŸå€ã®æåŸã®ç Š
// 2. ãã°: èªèšŒå€±æãå«ããå
šãªã¯ãšã¹ããèšé²
// 3. èªèšŒ: ä¿è·ã«ãŒããžã®ã¢ã¯ã»ã¹å¶åŸ¡ãã® 3 è¡ã®ã³ã¡ã³ããããã ãã§ãå幎åŸã®èªåãã
ããŒã ã¡ã³ããŒãããªããã®é çªãªã®ãããå³åº§ã«çè§£ã§ããŸãã
ãåå 3ã ã«ãŒããã³ãã©ã«ã¯ ãããããããšã ã ãæ®ã
ã«ãŒããã³ãã©ããããã°ãèªèšŒãã§ãã¯ãtry-catch ã远ãåºãã
æ®ãã®ã¯ããžãã¹ããžãã¯ã ãã
ã«ãŒããã³ãã©ããäœãããŠããããã 3 ç§ã§çè§£ã§ããç¶æ ã
ããããç©ã¿æšèšèšã®ãŽãŒã«ã§ãã
以åãServer Actions ã®ãå¢çããå
ã«æ±ºããããšããèšäºã§ã
ããªããŒã·ã§ã³ã»èªå¯ã»ãšã©ãŒã®ãã©ãã§ããããã
å
ã«æ±ºããéèŠæ§ãæžããŸããã
ä»åã®ããã«ãŠã§ã¢èšèšã¯ã
ãã®ææ³ã Hono ã® API ãµãŒã㌠ã«é©çšãããã®ã§ãã
ãã¬ãŒã ã¯ãŒã¯ã¯éã£ãŠããèšèšã®ååã¯åãã
ã責åãåé¢ããå±€ãéãããã
ãã®èãæ¹ã身ã«ã€ããšã
Next.js ã§ã Hono ã§ã Express ã§ãã
ã©ããªç°å¢ã§ãããªããšãªãããã忥ã§ããŸãã
ãç©ã¿æšã ã¯ã æªæ¥ã®èªåãå®ã
ãã€ãŠã®åã¯ãã«ãŒããã³ãã©ã«å
šéšæŒã蟌ãã§ããŸããã
ã³ããã§å¢æ®ãããã°åºåã埮åŠã«éãèªèšŒãã§ãã¯ã
çµ±äžãããŠããªããšã©ãŒã¬ã¹ãã³ã¹ã
ãåããŠããããããŸããããã
ããæã£ãŠãã 3 ã¶æåŸã®åã¯ã
èªåã®ã³ãŒããèªã¿ãããªããªã£ãŠããŸããã
ä»ã¯éããŸãã
æ°ãããšã³ããã€ã³ãã远å ãããšãã
åãããããšã¯ããžãã¹ããžãã¯ãæžãã ãã
ãã°ã¯åæã«æ®ãã
èªèšŒã¯ééæžã¿ã
ãšã©ãŒã¯æäžå±€ãåãæ¢ããŠãããã
ããªããšãªããã忥ãããã
ã³ãŒããèªã¿ããããªãã远å ãæããªããªãã
äœããéçºã楜ãããªããŸããã
ããä»ãããªãã® API ãµãŒããŒã®ã«ãŒããã³ãã©ã«
ããã°åºåããèªèšŒãã§ãã¯ããtry-catchããåå±
ããŠãããªãã
ãŸã㯠1 ã€ã ããããã«ãŠã§ã¢ãšããŠåãåºããŠã¿ãŠãã ããã
1 ã€åãåºãããã2 ã€ç®ãã
ãã㊠3 ã€ç®ãã
æ°ã¥ãã°ãããªãã®ã«ãŒããã³ãã©ã«ã¯
ãããããããšãã ããæ®ã£ãŠããã¯ãã§ãã
ããããŠèªã¿ãã
⌠ç©ã¿æšã®ãåå°ãââãšã©ãŒèšèšã®å ·äœçãªã³ãŒããšèãæ¹ãç¥ããããšãã«
ã«ã¹ã¿ã äŸå€ã¯ã©ã¹ãš onError ããã¯ã®å®è£
ãã¿ãŒã³ãã
ã³ããã§äœ¿ãã圢ã§å
¬éããŠããŸãã
ãã®èšäºã®ãç©ã¿æš 1: ãšã©ãŒãã³ããªã³ã°å±€ãã®è©³çްçã§ãã
⌠ãããããªã Hono ãªã®ãïŒ è»œããšéãã®é åãç¥ããããšãã«
å人éçºã«ããããéãé§ããè±ãæšãŠãåç¹ã®èšäºã
Hono ãéçºäœéšãã©ãå€ããŠãããã®ããåºäŒãã®ç©èªãç¶Žã£ãŠããŸãã
⌠Hono à Cloudflare ã§ããã©ãŒãã³ã¹ãäœæããããšãã«
ããã«ãŠã§ã¢èšèšãæŽãã API ãã
Cloudflare Workers ã«ãããã€ããŠçéãäœæããã
Hono ã®æ¬é ãåŒãåºãå®è·µçãªæ§æã玹ä»ããŠããŸãã
⌠Next.js åŽã§ã®ãèªå¯ãèšèšââããã«ãŠã§ã¢æèãããã³ããšã³ãã«å¿çšããããšãã«
NextAuth + Prisma ã§èªèšŒã»èªå¯ãæåã«èšèšããæ¹æ³ã
Hono ã®ããã«ãŠã§ã¢ãšåãããåŸåãã«ããªããèšèšææ³ã
ããã³ããšã³ãã«é©çšããèšäºã§ãã
⌠Server Actions ã®ãå¢çãââããªããŒã·ã§ã³ã»èªå¯ã»ãšã©ãŒãã©ãã§åŠçãããè¿·ã£ããšãã«
責åã®åé¢ãšãã©ãã§ãããããå
ã«æ±ºããã
ããã«ãŠã§ã¢ã®ç©ã¿æšèšèšãšåãååãã
Next.js ã® Server Actions ã«é©çšããå®è£
ã¬ã€ãã§ãã
⌠ç°å¢å€æ°ã®ãäºæ ããé²ããèšå®ç®¡çãéå£ã«ããããšãã«
ããã«ãŠã§ã¢ã®å€åŽã«ãããèšå®ãããäºæ
ã®æž©åºã«ãªããŸãã
Zod ã§ç°å¢å€æ°ãåå®å
šã«ç®¡çãã
èµ·åæã«èšå®æŒããæ€ç¥ããæ¹æ³ã解説ããŠããŸãã
⌠ãåãã°ãããããã®åæ¥ââãã¹ãã§å質ãå®ããããšãã«
ããã«ãŠã§ã¢ãåé¢ãããšããã¹ããæžãããããªããŸãã
ãåãã°ãããã§å°çãèŠãåãã
ãã¹ãã³ãŒãã«æããããŸã§ã®å€±æè«ãšåèµ·ã®èšé²ã§ãã
ã²ãšãããš
ãç©ã¿æšããšããæ¯å©ã«èŸ¿ãçããã®ã¯ã
å®ã¯çç²ãæ·¹ããŠãããšãã§ããã
è±ãæœããŠããã£ã«ã¿ãŒãã»ããããŠããæ¹¯ã泚ãã
ãã®æé ãå
¥ãæ¿ããããçç²ã«ã¯ãªããªãã
ãé çªã«æå³ãããã
ââåœããåã®ããšãªã®ã«ãã³ãŒãã«ãªããšå¿ããŠããŸãã
åãããªããšãªãããã«ãŠã§ã¢ãã忥ã§ããã®ã¯ã
ããªããã®é çªãªã®ãããèªåã®èšèã§
説æã§ããããã«ãªã£ãããã§ãã
ãã®èšäºãããªãã«ãšã£ãŠã
ããªããšãªããããæå³çã«ãã«å€ãã
ãã£ããã«ãªãããå¬ããã§ãã
