← スキル一覧に戻る

api-route
by InfinityBowman
CoRATES is an application designed to streamline the entire quality and risk-of-bias appraisal process.
⭐ 1🍴 0📅 2026年1月25日
SKILL.md
name: API Route description: This skill should be used when the user asks to "create an API route", "add an endpoint", "build a backend route", "create an API endpoint", "add a Hono route", or mentions creating REST endpoints, API handlers, or backend routes. Provides Hono API patterns for CoRATES workers.
API Route Creation
Create Hono API routes following CoRATES workers patterns.
Core Principles
- Middleware composition - Chain auth, permissions, validation middleware
- Domain errors - Use createDomainError from @corates/shared
- Zod validation - Define schemas centrally in config/validation.js
- Drizzle ORM - All database operations through Drizzle
- Context isolation - Attach data to Hono context, read via getters
Quick Reference
File Location
packages/workers/src/
routes/
[feature].js # Standalone routes
[feature]/
index.js # Route composition
[subroute].js # Nested routes
config/
validation.js # Zod schemas
middleware/
auth.js # Authentication
requireOrg.js # Org membership
Basic Route Template
import { Hono } from 'hono';
import { eq, and } from 'drizzle-orm';
import { createDb } from '@/db/client.js';
import { items } from '@/db/schema.js';
import { requireAuth, getAuth } from '@/middleware/auth.js';
import { validateRequest } from '@/config/validation.js';
import { createDomainError, ITEM_ERRORS, SYSTEM_ERRORS } from '@corates/shared';
import { itemSchemas } from '@/config/validation.js';
const itemRoutes = new Hono();
// Apply auth to all routes
itemRoutes.use('*', requireAuth);
// GET - List items
itemRoutes.get('/', async c => {
const { user } = getAuth(c);
const db = createDb(c.env.DB);
try {
const results = await db.select().from(items).where(eq(items.userId, user.id));
return c.json(results);
} catch (error) {
console.error('Error fetching items:', error);
const dbError = createDomainError(SYSTEM_ERRORS.DB_ERROR, {
operation: 'fetch_items',
});
return c.json(dbError, dbError.statusCode);
}
});
// POST - Create item
itemRoutes.post('/', validateRequest(itemSchemas.create), async c => {
const { user } = getAuth(c);
const { name, description } = c.get('validatedBody');
const db = createDb(c.env.DB);
try {
const id = crypto.randomUUID();
const now = new Date();
await db.insert(items).values({
id,
name,
description,
userId: user.id,
createdAt: now,
});
return c.json({ id, name, description }, 201);
} catch (error) {
console.error('Error creating item:', error);
const dbError = createDomainError(SYSTEM_ERRORS.DB_ERROR, {
operation: 'create_item',
});
return c.json(dbError, dbError.statusCode);
}
});
export { itemRoutes };
Middleware Chain
Apply middleware in order of specificity:
import { requireAuth, getAuth } from '@/middleware/auth.js';
import { requireOrgMembership, getOrgContext } from '@/middleware/requireOrg.js';
import { requireOrgWriteAccess } from '@/middleware/requireOrgWriteAccess.js';
import { requireEntitlement } from '@/middleware/requireEntitlement.js';
import { requireQuota } from '@/middleware/requireQuota.js';
import { validateRequest } from '@/config/validation.js';
// Full middleware chain for protected route
routes.post(
'/',
requireOrgMembership(), // Check org membership
requireOrgWriteAccess(), // Check write permission
requireEntitlement('feature.x'), // Check feature access
requireQuota('items.max', getItemCount, 1), // Check quota
validateRequest(schema), // Validate body
async c => {
const { user } = getAuth(c);
const { orgId } = getOrgContext(c);
const data = c.get('validatedBody');
// Handler code...
},
);
Context Getters
// Authentication
const { user, session } = getAuth(c);
// Organization context (after requireOrgMembership)
const { orgId, orgRole, org } = getOrgContext(c);
// Validated request body (after validateRequest)
const data = c.get('validatedBody');
// Billing/entitlements (after requireEntitlement)
const entitlements = c.get('entitlements');
const quotas = c.get('quotas');
Zod Validation
Define Schemas
Add to packages/workers/src/config/validation.js:
export const itemSchemas = {
create: z.object({
name: z
.string()
.min(1, 'Name is required')
.max(255)
.transform(val => val.trim()),
description: z
.string()
.max(2000)
.optional()
.transform(val => val?.trim() || null),
}),
update: z.object({
name: z.string().min(1).max(255).optional(),
description: z.string().max(2000).optional(),
}),
};
Common Patterns
// Required string with trim
name: z.string().min(1).max(255).transform(val => val.trim()),
// Optional with null fallback
description: z.string().max(2000).optional().transform(val => val?.trim() || null),
// Email
email: z.string().email('Invalid email'),
// UUID
id: z.string().uuid(),
// Enum
role: z.enum(['owner', 'admin', 'member', 'viewer']),
// Boolean with default
active: z.boolean().optional().default(true),
Error Handling
Domain Errors
import { createDomainError, PROJECT_ERRORS, AUTH_ERRORS, SYSTEM_ERRORS } from '@corates/shared';
// Not found
const error = createDomainError(PROJECT_ERRORS.NOT_FOUND, { projectId });
return c.json(error, error.statusCode);
// Forbidden with reason
const error = createDomainError(AUTH_ERRORS.FORBIDDEN, {
reason: 'insufficient_role',
required: 'admin',
});
return c.json(error, error.statusCode);
// Database error
const dbError = createDomainError(SYSTEM_ERRORS.DB_ERROR, {
operation: 'create_item',
originalError: error.message,
});
return c.json(dbError, dbError.statusCode);
Try-Catch Pattern
routes.get('/:id', async c => {
const { user } = getAuth(c);
const id = c.req.param('id');
const db = createDb(c.env.DB);
try {
const result = await db
.select()
.from(items)
.where(and(eq(items.id, id), eq(items.userId, user.id)))
.get();
if (!result) {
const error = createDomainError(ITEM_ERRORS.NOT_FOUND, { id });
return c.json(error, error.statusCode);
}
return c.json(result);
} catch (error) {
console.error('Error fetching item:', error);
const dbError = createDomainError(SYSTEM_ERRORS.DB_ERROR, {
operation: 'fetch_item',
});
return c.json(dbError, dbError.statusCode);
}
});
Database Operations
Query Patterns
import { createDb } from '@/db/client.js';
import { eq, and, or, like, desc, sql } from 'drizzle-orm';
const db = createDb(c.env.DB);
// Select with join
const results = await db
.select({
id: projects.id,
name: projects.name,
role: projectMembers.role,
})
.from(projects)
.innerJoin(projectMembers, eq(projects.id, projectMembers.projectId))
.where(eq(projectMembers.userId, user.id))
.orderBy(desc(projects.updatedAt));
// Single record
const item = await db
.select()
.from(items)
.where(eq(items.id, id))
.get();
// Insert
await db.insert(items).values({ id, name, createdAt: now });
// Update
await db.update(items)
.set({ name, updatedAt: now })
.where(eq(items.id, id));
// Delete
await db.delete(items).where(eq(items.id, id));
// Batch for atomic operations
await db.batch([
db.insert(projects).values({ ... }),
db.insert(projectMembers).values({ ... }),
]);
Response Patterns
// Success with data
return c.json(result);
// Created (201)
return c.json(newItem, 201);
// Success flag
return c.json({ success: true, id: itemId });
// Array response
return c.json(results);
// Error response
return c.json(error, error.statusCode);
Route Registration
Mount in Main App
// packages/workers/src/index.js
import { itemRoutes } from './routes/items.js';
app.route('/api/items', itemRoutes);
Nested Routes
// In parent route file
import { subRoutes } from './subroute.js';
parentRoutes.route('/:parentId/children', subRoutes);
// Creates: /api/parent/:parentId/children/...
Creation Checklist
When creating an API route:
- Create route file in
packages/workers/src/routes/ - Define Zod schemas in
config/validation.js - Apply appropriate middleware chain
- Use context getters for auth/org/validated data
- Use Drizzle for all database operations
- Return domain errors with proper status codes
- Register route in
index.js
Additional Resources
Reference Files
For detailed patterns:
references/patterns.md- Middleware details, complex queries, nested routesreferences/examples.md- Real route examples from the codebase
Example Files
Working templates in examples/:
ExampleRoutes.js- Complete CRUD route template
スコア
総合スコア
70/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
✓説明文
100文字以上の説明がある
+10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です