Skip to main content
hono-dev This skill should be used when building APIs with Hono, using hc client, implementing OpenAPI, or when "Hono", "RPC", or "type-safe API" are mentioned.
Ir para a instalação Skills Marketplace Descubra e explore skills de IA criadas pela comunidade.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Copiar promptMostrar detalhes do prompt Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
npx skills add https://github.com/outfitter-dev/agents --skill hono-devO comando permanece em uma só linha. Role horizontalmente para revisá-lo antes de copiar.
Prefere uma cópia local? Baixe os arquivos disponíveis atualmente no SkillsMP.
Baixar Zip Baixando... Mais deste repositório gitbutler-complete-branch This skill should be used when the user asks to "complete a branch", "merge to main", "finish my feature", "ship this branch", "integrate to main", "create a PR from GitButler", or when `--complete-branch` flag is mentioned. Guides completion of GitButler virtual branches with safety snapshots, integration workflows, and cleanup.
This skill should be used when coordinating multiple AI agents working concurrently, handling agent handoffs, transferring commits between agents, or when "multi-agent", "concurrent agents", "parallel agents", "agent collaboration", or "parallel execution" are mentioned with GitButler. Provides virtual branch patterns for parallel execution without coordination overhead.
This skill should be used when creating stacks, dependent branches, or when "stack", "stacked branches", "anchor", "--anchor", "but branch new -a", "create dependent branch", or "break feature into PRs" are mentioned with GitButler. Covers anchor-based stacking for dependent features and reviewable PR breakdown.
Ocupações relacionadas SOC
Baseado na classificação ocupacional SOC
Explorador de arquivos
7 arquivos name hono-dev description This skill should be used when building APIs with Hono, using hc client, implementing OpenAPI, or when "Hono", "RPC", or "type-safe API" are mentioned. metadata {"version":"1.0.0"}
Hono API Development
Route chaining → type-safe RPC → end-to-end types.
<when_to_use>
Building REST APIs with Hono
Type-safe RPC with hono/client
OpenAPI documentation with Zod
Testing APIs with testClient
When user mentions "Hono", "RPC", or "OpenAPI"
NOT for: Bun runtime APIs (use bun-dev), other frameworks (Express, Fastify)
</when_to_use>
<version_notes>
Hono v4+ with @hono/zod-openapi v1.0+
Check hono.dev for latest patterns.
</version_notes>
Route Chaining — Critical Pattern
Type inference flows through method chain. Break chain = lose types.
<route_chaining>
const app = new Hono ()
.get ('/users' , (c ) => c.json ({ users : [] }))
.get ('/users/:id' , (c ) => {
const id = c. . ( );
c. ({ id });
})
. ( , (c) => {
body = c. . ();
c. ({ : }, );
});
= app;
req
param
'id'
return
json
post
'/users'
async
const
await
req
json
return
json
created
true
201
export
type
AppType
typeof
const app = new Hono ();
app.get ('/users' , handler1);
app.post ('/users' , handler2);
Path parameters — typed automatically:
.get ('/posts/:id/comments/:commentId' , (c ) => {
const { id, commentId } = c.req .param ();
return c.json ({ postId : id, commentId });
})
Query parameters — use Zod for validation:
import { zValidator } from '@hono/zod-validator' ;
import { z } from 'zod' ;
const QuerySchema = z.object ({
page : z.coerce .number ().int ().positive ().default (1 ),
limit : z.coerce .number ().int ().positive ().max (100 ).default (20 ),
});
const app = new Hono ()
.get ('/search' , zValidator ('query' , QuerySchema ), (c ) => {
const { page, limit } = c.req .valid ('query' );
return c.json ({ page, limit });
});
const app = new Hono ()
.use ('*' , logger ())
.use ('/api/*' , cors ())
.get ('/api/public' , (c ) => c.json ({ public : true }))
.use ('/api/admin/*' , authMiddleware)
.get ('/api/admin/users' , (c ) => c.json ({ users : [] }));
Factory Pattern — Context Typing Use createFactory<Env>() to type context variables across middleware and routes.
import { createFactory } from 'hono/factory' ;
import type { Database } from 'bun:sqlite' ;
type Env = {
Variables : {
user : { id : string ; role : 'admin' | 'user' };
requestId : string ;
db : Database ;
};
};
const factory = createFactory<Env >();
const authMiddleware = factory.createMiddleware (async (c, next) => {
const token = c.req .header ('authorization' )?.replace ('Bearer ' , '' );
if (!token) throw new HTTPException (401 , { message : 'Unauthorized' });
const user = await verifyToken (token);
c.set ('user' , user);
await next ();
});
const getProfile = factory.createHandlers ((c ) => {
const user = c.get ('user' );
return c.json ({ user });
});
const app = factory.createApp ()
.use ('*' , dbMiddleware)
.use ('/api/*' , authMiddleware)
.get ('/api/profile' , ...getProfile);
export type AppType = typeof app;
export const usersRoute = factory.createApp ()
.get ('/' , (c ) => c.json ({ users : [] }))
.post ('/' , zValidator ('json' , CreateUserSchema ), async (c) => {
const data = c.req .valid ('json' );
return c.json ({ created : true }, 201 );
});
const app = factory.createApp ()
.use ('*' , dbMiddleware)
.route ('/users' , usersRoute)
.route ('/posts' , postsRoute);
Error Handling import { HTTPException } from 'hono/http-exception' ;
app.get ('/users/:id' , async (c) => {
const user = await findUser (c.req .param ('id' ));
if (!user) {
throw new HTTPException (404 , { message : 'User not found' });
}
return c.json ({ user });
});
class NotFoundError extends HTTPException {
constructor (resource : string ) {
super (404 , { message : `${resource} not found` });
}
}
class UnauthorizedError extends HTTPException {
constructor (message = 'Unauthorized' ) {
super (401 , { message });
}
}
app.onError ((err, c ) => {
if (err instanceof HTTPException ) {
return c.json ({ error : err.message }, err.status );
}
if (err instanceof ZodError ) {
return c.json ({
error : 'Validation failed' ,
issues : err.issues .map (i => ({ path : i.path .join ('.' ), message : i.message }))
}, 400 );
}
const isDev = Bun .env .NODE_ENV !== 'production' ;
return c.json ({ error : isDev ? err.message : 'Internal server error' }, 500 );
});
app.notFound ((c ) => c.json ({ error : 'Not found' , path : c.req .path }, 404 ));
Zod OpenAPI import { createRoute, OpenAPIHono , z } from '@hono/zod-openapi' ;
import { swaggerUI } from '@hono/swagger-ui' ;
const UserSchema = z.object ({
id : z.string ().uuid (),
email : z.string ().email (),
name : z.string ().min (1 ).max (100 ),
}).openapi ('User' );
const route = createRoute ({
method : 'get' ,
path : '/users/{id}' ,
request : {
params : z.object ({ id : z.string ().uuid () }),
},
responses : {
200 : {
content : { 'application/json' : { schema : UserSchema } },
description : 'User found' ,
},
404 : {
content : { 'application/json' : { schema : z.object ({ error : z.string () }) } },
description : 'User not found' ,
},
},
tags : ['Users' ],
summary : 'Get user by ID' ,
});
const app = new OpenAPIHono ();
app.openapi (route, (c ) => {
const { id } = c.req .valid ('param' );
const user = db.query ('SELECT * FROM users WHERE id = ?' ).get (id);
if (!user) return c.json ({ error : 'User not found' }, 404 );
return c.json (user, 200 );
});
app.get ('/docs' , swaggerUI ({ url : '/openapi.json' }));
app.doc ('/openapi.json' , {
openapi : '3.1.0' ,
info : { title : 'API' , version : '1.0.0' },
});
RPC Client — End-to-End Types
const app = new Hono ()
.get ('/posts' , (c ) => c.json ({ posts : [] }))
.get ('/posts/:id' , (c ) => c.json ({ id : c.req .param ('id' ) }))
.post ('/posts' , zValidator ('json' , CreatePostSchema ), async (c) => {
const data = c.req .valid ('json' );
return c.json ({ id : '123' , ...data }, 201 );
});
export type AppType = typeof app;
import { hc } from 'hono/client' ;
import type { AppType } from './server' ;
const client = hc<AppType >('http://localhost:3000' );
const res = await client.posts .$get();
const data = await res.json ();
const res2 = await client.posts [':id' ].$get({ param : { id : '123' } });
const res3 = await client.posts .$post({
json : { title : 'Hello' , content : 'World' }
});
const res4 = await client.posts .$get({}, {
headers : { Authorization : 'Bearer token' }
});
Testing with testClient import { describe, expect, test, beforeEach, afterEach } from 'bun:test' ;
import { testClient } from 'hono/testing' ;
import { Database } from 'bun:sqlite' ;
import app from './server' ;
describe ('API Tests' , () => {
let db : Database ;
beforeEach (() => {
db = new Database (':memory:' );
db.run ('CREATE TABLE posts (id TEXT PRIMARY KEY, title TEXT, content TEXT)' );
});
afterEach (() => {
db.close ();
});
const client = testClient (app);
test ('GET /posts returns posts' , async () => {
const res = await client.posts .$get();
expect (res.status ).toBe (200 );
const data = await res.json ();
expect (data).toHaveProperty ('posts' );
});
test ('POST /posts creates post' , async () => {
const res = await client.posts .$post({
json : { title : 'Test' , content : 'Content' }
});
expect (res.status ).toBe (201 );
const data = await res.json ();
expect (data).toMatchObject ({ title : 'Test' });
});
test ('Protected route requires auth' , async () => {
const res = await client.api .profile .$get();
expect (res.status ).toBe (401 );
});
test ('Protected route accepts valid token' , async () => {
const res = await client.api .profile .$get({}, {
headers : { Authorization : 'Bearer valid-token' }
});
expect (res.status ).toBe (200 );
});
});
Middleware Patterns
import { logger } from 'hono/logger' ;
app.use ('*' , logger ());
import { cors } from 'hono/cors' ;
app.use ('/api/*' , cors ({
origin : ['http://localhost:3000' ],
credentials : true ,
}));
const rateLimiter = factory.createMiddleware (async (c, next) => {
const ip = c.req .header ('x-forwarded-for' ) || 'unknown' ;
const key = `rate:${ip} ` ;
const count = await cache.incr (key);
if (count === 1 ) await cache.expire (key, 60 );
if (count > 100 ) {
throw new HTTPException (429 , { message : 'Rate limit exceeded' });
}
await next ();
});
const requestId = factory.createMiddleware (async (c, next) => {
c.set ('requestId' , crypto.randomUUID ());
await next ();
c.res .headers .set ('x-request-id' , c.get ('requestId' ));
});
Rules
Chain routes for type inference → .get().post().put()
Export type AppType = typeof app for RPC client
Use createFactory<Env>() for typed context variables
Validate with Zod schemas via zValidator
Handle errors with HTTPException and centralized onError
Test with testClient for type safety
Break method chain with variable assignment between routes
Use any types — let Hono infer or define explicitly
Use JSON.parse(await c.req.text()) — use c.req.json() or Zod validator
Skip request validation on user input
Expose stack traces in production
Check route chaining not broken
Verify export type AppType matches actual app
Ensure middleware uses createFactory for context types
Check client using correct param, query, or json keys
References