Skip to main content Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill hono-rpc명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills LinkedIn automation via the Linked API CLI - fetch profiles, search people and companies, send messages, manage connections, create posts, react, comment, and run Sales Navigator and custom workflows. Use when the user wants to interact with LinkedIn.
Xquik X data automation API - Use REST or MCP for tweet search, user lookup, follower exports, media downloads, monitors, webhooks, giveaway draws, and confirmation-gated X actions.
MCP (Model Context Protocol) - Build AI-native servers with tools, resources, and prompts. TypeScript/Python SDKs for Claude Desktop integration.
name hono-rpc description Hono RPC - end-to-end type-safe API client generation with hc client and TypeScript inference user-invocable false disable-model-invocation true skill_version 1.0.0 updated_at "2025-01-03T00:00:00.000Z" tags ["hono","rpc","type-safety","typescript","api-client","full-stack"] progressive_disclosure {"entry_point":{"summary":"End-to-end type-safe API client with automatic TypeScript inference from server routes","when_to_use":"Building full-stack TypeScript apps where client needs type-safe API access","quick_start":"1. Export AppType from server 2. Import hc client 3. Use typed client methods"},"references":[]} context_limit 800
Hono RPC - Type-Safe Client
Overview
Hono RPC enables sharing API specifications between server and client through TypeScript's type system. Export your server's type, and the client automatically knows all routes, request shapes, and response types - no code generation required.
Key Features :
Zero-codegen type-safe client
Automatic TypeScript inference
Works with Zod validators
Status code-aware response types
Supports path params, query, headers
When to Use This Skill
Use Hono RPC when:
Building full-stack TypeScript applications
Need type-safe API consumption without OpenAPI/codegen
Want compile-time validation of API calls
Sharing types between client and server in monorepos
Basic Setup
Server Side
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
const app = new Hono ()
const route = app
.get ('/users' , async (c) => {
const users = [{ id : '1' , name : 'Alice' }]
return c.json ({ users })
})
.post (
'/users' ,
zValidator ('json' , z.object ({
name : z.string (),
: z. (). ()
})),
(c) => {
data = c. . ( )
c. ({ : , ...data }, )
}
)
. ( , (c) => {
id = c. . ( )
c. ({ id, : })
})
= route
app
email
string
email
async
const
req
valid
'json'
return
json
id
'1'
201
get
'/users/:id'
async
const
req
param
'id'
return
json
name
'Alice'
export
type
AppType
typeof
export
default
Client Side
import { hc } from 'hono/client'
import type { AppType } from '../server'
const client = hc<AppType >('http://localhost:3000' )
async function examples ( ) {
const usersRes = await client.users .$get()
const { users } = await usersRes.json ()
const createRes = await client.users .$post({
json : {
name : 'Bob' ,
email : 'bob@example.com'
}
})
const created = await createRes.json ()
const userRes = await client.users [':id' ].$get({
param : { id : '123' }
})
const user = await userRes.json ()
}
Route Chaining for Type Export Important : Chain routes for proper type inference:
const route = app
.get ('/a' , handlerA)
.post ('/b' , handlerB)
.get ('/c' , handlerC)
export type AppType = typeof route
app.get ('/a' , handlerA)
app.post ('/b' , handlerB)
export type AppType = typeof app
Request Patterns
Path Parameters
const route = app.get ('/posts/:postId/comments/:commentId' , async (c) => {
const { postId, commentId } = c.req .param ()
return c.json ({ postId, commentId })
})
const res = await client.posts [':postId' ].comments [':commentId' ].$get({
param : {
postId : '1' ,
commentId : '42'
}
})
Query Parameters
const route = app.get (
'/search' ,
zValidator ('query' , z.object ({
q : z.string (),
page : z.coerce .number ().optional (),
limit : z.coerce .number ().optional ()
})),
async (c) => {
const { q, page, limit } = c.req .valid ('query' )
return c.json ({ query : q, page, limit })
}
)
const res = await client.search .$get({
query : {
q : 'typescript' ,
page : 1 ,
limit : 20
}
})
JSON Body
const route = app.post (
'/posts' ,
zValidator ('json' , z.object ({
title : z.string (),
content : z.string (),
tags : z.array (z.string ()).optional ()
})),
async (c) => {
const data = c.req .valid ('json' )
return c.json ({ id : '1' , ...data }, 201 )
}
)
const res = await client.posts .$post({
json : {
title : 'Hello World' ,
content : 'My first post' ,
tags : ['typescript' , 'hono' ]
}
})
Form Data
const route = app.post (
'/upload' ,
zValidator ('form' , z.object ({
file : z.instanceof (File ),
description : z.string ().optional ()
})),
async (c) => {
const { file, description } = c.req .valid ('form' )
return c.json ({ filename : file.name })
}
)
const formData = new FormData ()
formData.append ('file' , file)
formData.append ('description' , 'My file' )
const res = await client.upload .$post({
form : formData
})
Headers
const route = app.get (
'/protected' ,
zValidator ('header' , z.object ({
authorization : z.string ()
})),
async (c) => {
return c.json ({ authenticated : true })
}
)
const res = await client.protected .$get({
header : {
authorization : 'Bearer token123'
}
})
Response Type Inference
Status Code-Aware Types
const route = app.get ('/user' , async (c) => {
const user = await getUser ()
if (!user) {
return c.json ({ error : 'Not found' }, 404 )
}
return c.json ({ id : user.id , name : user.name }, 200 )
})
import { InferResponseType } from 'hono/client'
type SuccessResponse = InferResponseType <typeof client.user .$get , 200 >
type ErrorResponse = InferResponseType <typeof client.user .$get , 404 >
const res = await client.user .$get()
if (res.status === 200 ) {
const data = await res.json ()
} else if (res.status === 404 ) {
const error = await res.json ()
}
Request Type Inference import { InferRequestType } from 'hono/client'
type CreateUserRequest = InferRequestType <typeof client.users .$post >['json' ]
const [formData, setFormData] = useState<CreateUserRequest >({
name : '' ,
email : ''
})
Multi-File Route Organization
Organize Routes
import { Hono } from 'hono'
export const users = new Hono ()
.get ('/' , async (c) => c.json ({ users : [] }))
.post ('/' , async (c) => c.json ({ created : true }, 201 ))
.get ('/:id' , async (c) => c.json ({ id : c.req .param ('id' ) }))
export const posts = new Hono ()
.get ('/' , async (c) => c.json ({ posts : [] }))
.post ('/' , async (c) => c.json ({ created : true }, 201 ))
import { Hono } from 'hono'
import { users } from './routes/users'
import { posts } from './routes/posts'
const app = new Hono ()
const route = app
.route ('/users' , users)
.route ('/posts' , posts)
export type AppType = typeof route
export default app
Client Usage import { hc } from 'hono/client'
import type { AppType } from '../server'
const client = hc<AppType >('http://localhost:3000' )
await client.users .$get()
await client.users [':id' ].$get()
await client.posts .$get()
Error Handling
Handle Fetch Errors async function fetchUser (id : string ) {
try {
const res = await client.users [':id' ].$get({
param : { id }
})
if (!res.ok ) {
const error = await res.json ()
throw new Error (error.message || 'Failed to fetch user' )
}
return await res.json ()
} catch (error) {
if (error instanceof TypeError ) {
throw new Error ('Network error' )
}
throw error
}
}
Type-Safe Error Responses
const route = app.get ('/resource' , async (c) => {
try {
const data = await fetchData ()
return c.json ({ success : true , data })
} catch (e) {
return c.json ({ success : false , error : 'Failed' }, 500 )
}
})
type ApiResponse <T> =
| { success : true ; data : T }
| { success : false ; error : string }
const res = await client.resource .$get()
const result : ApiResponse <DataType > = await res.json ()
if (result.success ) {
console .log (result.data )
} else {
console .error (result.error )
}
Configuration Options
Custom Fetch const client = hc<AppType >('http://localhost:3000' , {
fetch : async (input, init) => {
console .log ('Fetching:' , input)
return fetch (input, init)
}
})
Default Headers const client = hc<AppType >('http://localhost:3000' , {
headers : {
'Authorization' : 'Bearer token' ,
'X-Custom-Header' : 'value'
}
})
Dynamic Headers const getClient = (token : string ) =>
hc<AppType >('http://localhost:3000' , {
headers : () => ({
'Authorization' : `Bearer ${token} `
})
})
const client = hc<AppType >('http://localhost:3000' , {
headers : () => {
const token = getAuthToken ()
return token ? { 'Authorization' : `Bearer ${token} ` } : {}
}
})
Best Practices
1. Enable Strict Mode
{
"compilerOptions" : {
"strict" : true
}
}
2. Use Explicit Status Codes
return c.json ({ data }, 200 )
return c.json ({ error : 'Not found' }, 404 )
return c.notFound ()
3. Split Large Apps
const v1 = new Hono ()
.route ('/users' , usersRoute)
.route ('/posts' , postsRoute)
const v2 = new Hono ()
.route ('/users' , usersV2Route)
export type V1Type = typeof v1
export type V2Type = typeof v2
4. Consistent Response Shapes
type ApiSuccess <T> = { ok : true ; data : T }
type ApiError = { ok : false ; error : string ; code ?: string }
type ApiResponse <T> = ApiSuccess <T> | ApiError
const route = app.get ('/users/:id' , async (c) => {
const user = await findUser (c.req .param ('id' ))
if (!user) {
return c.json ({ ok : false , error : 'User not found' } as ApiError , 404 )
}
return c.json ({ ok : true , data : user } as ApiSuccess <User >, 200 )
})
Quick Reference
Client Methods HTTP Method Client Method GET client.path.$get()POST client.path.$post()PUT client.path.$put()DELETE client.path.$delete()PATCH client.path.$patch()
Request Options client.path .$method({
param : { id : '1' },
query : { page : 1 },
json : { name : 'Alice' },
form : formData,
header : { 'X-Custom' : 'v' }
})
Type Utilities import { InferRequestType , InferResponseType } from 'hono/client'
type ReqType = InferRequestType <typeof client.users .$post >
type Res200 = InferResponseType <typeof client.users .$get , 200 >
type Res404 = InferResponseType <typeof client.users .$get , 404 >
Related Skills
hono-core - Framework fundamentals
hono-validation - Request validation
typescript-core - TypeScript patterns
Version : Hono 4.x
Last Updated : January 2025
License : MIT