{"id":"hono-api-scaffolder","name":"hono-api-scaffolder","summary":"Cloudflare WorkersのためのScaffold Hono APIルート。ルートファイル、ミドルウェア、タイプバインディング、Zod検証、エラー処理、API_ENDPOINTS.mdドキュメントの作成。","body":"# Hono API Scaffolder\n\nAdd structured API routes to an existing Cloudflare Workers project. This skill runs AFTER the project shell exists (via cloudflare-worker-builder or vite-flare-starter) and produces route files, middleware, and endpoint documentation.\n\n## Workflow\n\n### Step 1: Gather Endpoints\n\nDetermine what the API needs. Either ask the user or infer from the project description. Group endpoints by resource:\n\n```\nUsers:    GET /api/users, GET /api/users/:id, POST /api/users, PUT /api/users/:id, DELETE /api/users/:id\nPosts:    GET /api/posts, GET /api/posts/:id, POST /api/posts, PUT /api/posts/:id\nAuth:     POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me\n```\n\n### Step 2: Create Route Files\n\nOne file per resource group. Use the template from [assets/route-template.ts](assets/route-template.ts):\n\n```typescript\n// src/routes/users.ts\nimport { Hono } from 'hono'\nimport { zValidator } from '@hono/zod-validator'\nimport { z } from 'zod'\nimport type { Env } from '../types'\n\nconst app = new Hono<{ Bindings: Env }>()\n\n// GET /api/users\napp.get('/', async (c) => {\n  const db = c.env.DB\n  const { results } = await db.prepare('SELECT * FROM users').all()\n  return c.json({ users: results })\n})\n\n// GET /api/users/:id\napp.get('/:id', async (c) => {\n  const id = c.req.param('id')\n  const user = await db.prepare('SELECT * FROM users WHERE id = ?').bind(id).first()\n  if (!user) return c.json({ error: 'Not found' }, 404)\n  return c.json({ user })\n})\n\n// POST /api/users\nconst createUserSchema = z.object({\n  name: z.string().min(1),\n  email: z.string().email(),\n})\n\napp.post('/', zValidator('json', createUserSchema), async (c) => {\n  const body = c.req.valid('json')\n  // ... insert logic\n  return c.json({ user }, 201)\n})\n\nexport default app\n```\n\n### Step 3: Add Middleware\n\nBased on project needs, add from [assets/middleware-template.ts](assets/middleware-template.ts):\n\n**Auth middleware** — protect routes requiring authentication:\n```typescript\nimport { createMiddleware } from 'hono/factory'\nimport type { Env } from '../types'\n\nexport const requireAuth = createMiddleware<{ Bindings: Env }>(async (c, next) => {\n  const token = c.req.header('Authorization')?.replace('Bearer ', '')\n  if (!token) return c.json({ error: 'Unauthorized' }, 401)\n  // Validate token...\n  await next()\n})\n```\n\n**CORS** — use Hono's built-in:\n```typescript\nimport { cors } from 'hono/cors'\napp.use('/api/*', cors({ origin: ['https://example.com'] }))\n```\n\n### Step 4: Wire Routes\n\nMount all route groups in the main entry point:\n\n```typescript\n// src/index.ts\nimport { Hono } from 'hono'\nimport type { Env } from './types'\nimport users from './routes/users'\nimport posts from './routes/posts'\nimport auth from './routes/auth'\nimport { errorHandler } from './middleware/error-handler'\n\nconst app = new Hono<{ Bindings: Env }>()\n\n// Global error handler\napp.onError(errorHandler)\n\n// Mount routes\napp.route('/api/users', users)\napp.route('/api/posts', posts)\napp.route('/api/auth', auth)\n\n// Health check\napp.get('/api/health', (c) => c.json({ status: 'ok' }))\n\nexport default app\n```\n\n### Step 5: Create Types\n\n```typescript\n// src/types.ts\nexport interface Env {\n  DB: D1Database\n  KV: KVNamespace      // if needed\n  R2: R2Bucket         // if needed\n  API_SECRET: string   // secrets\n}\n```\n\n### Step 6: Generate API_ENDPOINTS.md\n\nDocument all endpoints. See [references/endpoint-docs-template.md](references/endpoint-docs-template.md) for the format:\n\n```markdown\n## POST /api/users\nCreate a new user.\n- **Auth**: Required (Bearer token)\n- **Body**: `{ name: string, email: string }`\n- **Response 201**: `{ user: User }`\n- **Response 400**: `{ error: string, details: ZodError }`\n```\n\n## Key Patterns\n\n### Zod Validation\n\nAlways validate request bodies with `@hono/zod-validator`:\n\n```typescript\nimport { zValidator } from '@hono/zod-validator'\napp.post('/', zValidator('json', schema), async (c) => {\n  const body = c.req.valid('json')  // fully typed\n})\n```\n\nInstall: `pnpm add @hono/zod-validator zod`\n\n### Error Handling\n\nUse the standard error handler from [assets/error-handler.ts](assets/error-handler.ts):\n\n```typescript\nexport const errorHandler = (err: Error, c: Context) => {\n  console.error(err)\n  return c.json({ error: err.message }, 500)\n}\n```\n\n**API routes must return JSON errors, not redirects.** `fetch()` follows redirects silently, then the client tries to parse HTML as JSON.\n\n### RPC Type Safety\n\nFor end-to-end type safety between Worker and client:\n\n```typescript\n// Worker: export the app type\nexport type AppType = typeof app\n\n// Client: use hc (Hono Client)\nimport { hc } from 'hono/client'\nimport type { AppType } from '../worker/src/index'\n\nconst client = hc<AppType>('https://api.example.com')\nconst res = await client.api.users.$get()  // fully typed\n```\n\n### Route Groups vs Single File\n\n| Project size | Structure |\n|-------------|-----------|\n| < 10 endpoints | Single `index.ts` with all routes |\n| 10-30 endpoints | Route files per resource (`routes/users.ts`) |\n| 30+ endpoints | Route files + shared middleware + typed context |\n\n## Reference Files\n\n| When | Read |\n|------|------|\n| Hono patterns, middleware, RPC | [references/hono-patterns.md](references/hono-patterns.md) |\n| API_ENDPOINTS.md format | [references/endpoint-docs-template.md](references/endpoint-docs-template.md) |\n\n## Assets\n\n| File | Purpose |\n|------|---------|\n| [assets/route-template.ts](assets/route-template.ts) | Starter route file with CRUD + Zod |\n| [assets/middleware-template.ts](assets/middleware-template.ts) | Auth middleware template |\n| [assets/error-handler.ts](assets/error-handler.ts) | Standard JSON error handler |","author":"@jezweb","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/jezweb/claude-skills/tree/main/plugins/cloudflare/skills/hono-api-scaffolder","license":"MIT","category":"coding","lang":"en","tokens":1463,"stars":0,"calls30d":1,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"assets/error-handler.ts","size":474,"sha256":"12a7c117f5649ce56779dff2d5f3f133e5656306104c8e032fae2c57509af00d"},{"path":"assets/middleware-template.ts","size":776,"sha256":"6b0eb1942bd69d8da79dc2cfdf600fbe009fd22773f03e4e56743458599c02a9"},{"path":"assets/route-template.ts","size":1727,"sha256":"65283ca8e8b09eff981e456bb462f73eb6f02ace91252275087f0d860e2c4920"},{"path":"references/endpoint-docs-template.md","size":2230,"sha256":"2ee6a2882d9a0f2aa4e0a114988e10fb38451ac4539e23712c65970d44bf5f82"},{"path":"references/hono-patterns.md","size":4614,"sha256":"50d4587f3e2f168da57d915d3bfb7fa1529091553b1f9e0e16421227200528b0"}],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[{"code":"net.endpoints","kind":"exfiltration","excerpt":"api.example.com","message":"bundled scripts reach 1 external host(s)","severity":"warn"}],"scannedAt":"2026-08-22","hasScripts":true,"networkEndpoints":["api.example.com"]}}