create-controller
について
このスキルは、リクエスト/レスポンスのロジックを処理し、ルートをサービスに接続するHTTPコントローラーファイルを生成します。既存のスキーマとサービスに基づいて、適切なインポート、メソッドスタブ、バリデーションを含むTypeScriptコントローラーを作成します。スキーマとサービスレイヤーを設定した後、APIエンドポイントを実装する必要がある場合にご利用ください。
クイックインストール
Claude Code
推奨/plugin add https://github.com/majiayu000/claude-skill-registrygit clone https://github.com/majiayu000/claude-skill-registry.git ~/.claude/skills/create-controllerこのコマンドをClaude Codeにコピー&ペーストしてスキルをインストールします
ドキュメント
Create Controller
Creates a controller that handles HTTP requests and responses. Controllers are thin layers that extract data from requests, call services, and return responses.
Quick Reference
Location: src/controllers/{entity-name}.controller.ts
Naming: Singular, kebab-case (e.g., note.controller.ts, user.controller.ts)
Prerequisites
Before creating a controller, ensure you have:
- Schema created with request/response types (
src/schemas/{entity-name}.schema.ts) - Service created (
src/services/{entity-name}.service.ts)
Instructions
Step 1: Create the Controller File
Create src/controllers/{entity-name}.controller.ts
Step 2: Import Dependencies
import type { Context } from "hono";
import { {Entity}Service } from "@/services/{entity-name}.service";
import type { EntityIdParamType } from "@/schemas/shared.schema";
import type {
Create{Entity}Type,
{Entity}QueryParamsType,
Update{Entity}Type,
} from "@/schemas/{entity-name}.schema";
import type { AppEnv } from "@/schemas/app-env.schema";
import type { AuthenticatedUserContextType } from "@/schemas/user.schemas";
import { NotFoundError } from "@/errors";
Step 3: Create the Controller Class
export class {Entity}Controller {
private {entity}Service: {Entity}Service;
constructor({entity}Service?: {Entity}Service) {
if ({entity}Service) {
this.{entity}Service = {entity}Service;
} else {
this.{entity}Service = new {Entity}Service();
}
}
// Handler methods...
}
Step 4: Implement CRUD Handlers
getAll
getAll = async (c: Context<AppEnv>): Promise<Response> => {
const user = c.var.user as AuthenticatedUserContextType;
const query = c.var.validatedQuery as {Entity}QueryParamsType;
const {entities} = await this.{entity}Service.getAll(query, user);
return c.json({entities});
};
getById
getById = async (c: Context<AppEnv>): Promise<Response> => {
const user = c.var.user as AuthenticatedUserContextType;
const { id } = c.var.validatedParams as EntityIdParamType;
const {entity} = await this.{entity}Service.getById(id, user);
if (!{entity}) throw new NotFoundError();
return c.json({entity});
};
create
create = async (c: Context<AppEnv>): Promise<Response> => {
const user = c.var.user as AuthenticatedUserContextType;
const body = c.var.validatedBody as Create{Entity}Type;
const {entity} = await this.{entity}Service.create(body, user);
return c.json({entity});
};
update
update = async (c: Context<AppEnv>): Promise<Response> => {
const user = c.var.user as AuthenticatedUserContextType;
const { id } = c.var.validatedParams as EntityIdParamType;
const body = c.var.validatedBody as Update{Entity}Type;
const {entity} = await this.{entity}Service.update(id, body, user);
if (!{entity}) throw new NotFoundError();
return c.json({entity});
};
delete
delete = async (c: Context<AppEnv>): Promise<Response> => {
const user = c.var.user as AuthenticatedUserContextType;
const { id } = c.var.validatedParams as EntityIdParamType;
const success = await this.{entity}Service.delete(id, user);
if (!success) throw new NotFoundError();
return c.json({ message: "{Entity} deleted successfully" });
};
Patterns & Rules
Handler Method Pattern
Use arrow functions assigned to class properties for handlers:
// Correct - arrow function maintains `this` binding
getAll = async (c: Context<AppEnv>): Promise<Response> => {
// ...
};
// Wrong - regular method loses `this` when passed as callback
async getAll(c: Context<AppEnv>): Promise<Response> {
// ...
}
Context Variables
Data is pre-validated by middleware and stored in c.var:
// User from auth middleware
const user = c.var.user as AuthenticatedUserContextType;
// Validated query params from validation middleware
const query = c.var.validatedQuery as {Entity}QueryParamsType;
// Validated request body from validation middleware
const body = c.var.validatedBody as Create{Entity}Type;
// Validated URL params from validation middleware
const { id } = c.var.validatedParams as EntityIdParamType;
Dependency Injection
Allow service injection for testing:
constructor({entity}Service?: {Entity}Service) {
if ({entity}Service) {
this.{entity}Service = {entity}Service;
} else {
this.{entity}Service = new {Entity}Service();
}
}
Error Handling
Controllers throw domain errors - global error handler converts to HTTP:
// Service returns null for not found
const {entity} = await this.{entity}Service.getById(id, user);
if (!{entity}) throw new NotFoundError();
// Service throws UnauthorizedError for permission denied
// Let it propagate - global handler catches it
Response Format
Use c.json() for all responses:
// Return entity
return c.json({ entity });
// Return paginated result
return c.json({ entities }); // { data: [...], total: n, page: 1, ... }
// Return success message
return c.json({ message: "{Entity} deleted successfully" });
AppEnv Type
Always type Context with AppEnv:
import type { AppEnv } from "@/schemas/app-env.schema";
getAll = async (c: Context<AppEnv>): Promise<Response> => {
// c.var is properly typed
};
The AppEnv interface provides types for:
c.var.user- Authenticated user contextc.var.validatedQuery- Validated query parametersc.var.validatedBody- Validated request bodyc.var.validatedParams- Validated URL parameters
Complete Example
See REFERENCE.md for a complete NoteController implementation.
What NOT to Do
- Do NOT validate input in controllers (use validation middleware)
- Do NOT access
c.req.json()directly (usec.var.validatedBody) - Do NOT catch errors (let global error handler catch them)
- Do NOT return HTTP status codes manually (use domain errors)
- Do NOT put business logic in controllers (that's for services)
- Do NOT use regular methods (use arrow functions for
thisbinding)
See Also
create-routes- Wire controller handlers to routes with middlewarecreate-middleware- Create validation and auth middlewaretest-controller- Test controller handlers
GitHub リポジトリ
関連スキル
algorithmic-art
メタThis Claude Skill creates original algorithmic art using p5.js with seeded randomness and interactive parameters. It generates .md files for algorithmic philosophies, plus .html and .js files for interactive generative art implementations. Use it when developers need to create flow fields, particle systems, or other computational art while avoiding copyright issues.
subagent-driven-development
開発This skill executes implementation plans by dispatching a fresh subagent for each independent task, with code review between tasks. It enables fast iteration while maintaining quality gates through this review process. Use it when working on mostly independent tasks within the same session to ensure continuous progress with built-in quality checks.
executing-plans
デザインUse the executing-plans skill when you have a complete implementation plan to execute in controlled batches with review checkpoints. It loads and critically reviews the plan, then executes tasks in small batches (default 3 tasks) while reporting progress between each batch for architect review. This ensures systematic implementation with built-in quality control checkpoints.
cost-optimization
その他This Claude Skill helps developers optimize cloud costs through resource rightsizing, tagging strategies, and spending analysis. It provides a framework for reducing cloud expenses and implementing cost governance across AWS, Azure, and GCP. Use it when you need to analyze infrastructure costs, right-size resources, or meet budget constraints.
