api-route-creator
Creates Next.js 16 API routes with auth, validation, and tenant scoping. Use when creating API endpoints.
Best use case
api-route-creator is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Creates Next.js 16 API routes with auth, validation, and tenant scoping. Use when creating API endpoints.
Teams using api-route-creator should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/api-route-creator/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How api-route-creator Compares
| Feature / Agent | api-route-creator | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Creates Next.js 16 API routes with auth, validation, and tenant scoping. Use when creating API endpoints.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# API Route Creation Skill
## When to Use
Use this skill when creating:
- New API endpoints
- Route handlers
- Server actions
## Security Requirements (NEVER VIOLATE)
1. **Always authenticate** - Check session
2. **Always scope by tenant** - Use session.user.tenantId
3. **Always validate input** - Use Zod schemas
4. **Never trust user input** - Especially tenant_id
5. **Log sensitive ops** - Audit trail
## Template: API Route Handler
```typescript
import { NextRequest, NextResponse } from 'next/server';
import { auth } from '@/lib/auth/config';
import { z } from 'zod';
import { db } from '@/lib/db';
import { eq, and } from 'drizzle-orm';
import { tableName } from '@/lib/db/schema';
import { auditLogger } from '@/lib/audit/logger';
// Input validation schema
const inputSchema = z.object({
name: z.string().min(1).max(100).trim(),
description: z.string().max(500).optional(),
});
// GET - Read (with tenant scoping)
export async function GET(request: NextRequest) {
try {
const session = await auth();
// Authentication check
if (!session?.user) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
// Role check (if needed)
if (!['teacher', 'tenant_admin'].includes(session.user.role)) {
return NextResponse.json(
{ error: 'Forbidden' },
{ status: 403 }
);
}
// ✅ CRITICAL: Always scope by tenant
const data = await db.query.tableName.findMany({
where: eq(tableName.tenantId, session.user.tenantId),
});
return NextResponse.json({ data });
} catch (error) {
console.error('[API] Error:', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
// POST - Create
export async function POST(request: NextRequest) {
try {
const session = await auth();
if (!session?.user) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
// Parse and validate input
const body = await request.json();
const validatedInput = inputSchema.parse(body);
// ✅ CRITICAL: Use session tenant, NEVER request body
const [created] = await db.insert(tableName).values({
...validatedInput,
tenantId: session.user.tenantId, // FROM SESSION ONLY
createdBy: session.user.id,
}).returning();
// Audit log sensitive operations
await auditLogger.log({
action: 'CREATE',
resourceType: 'RESOURCE_NAME',
resourceId: created.id,
userId: session.user.id,
tenantId: session.user.tenantId,
});
return NextResponse.json({ data: created }, { status: 201 });
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation error', details: error.errors },
{ status: 400 }
);
}
console.error('[API] Error:', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
```
## Template: Dynamic Route ([id])
```typescript
import { NextRequest, NextResponse } from 'next/server';
import { auth } from '@/lib/auth/config';
import { db } from '@/lib/db';
import { eq, and } from 'drizzle-orm';
import { tableName } from '@/lib/db/schema';
interface RouteContext {
params: Promise<{ id: string }>;
}
export async function GET(
request: NextRequest,
context: RouteContext
) {
try {
const session = await auth();
if (!session?.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// ✅ Await params in Next.js 16
const { id } = await context.params;
// ✅ CRITICAL: Scope by BOTH id AND tenant
const item = await db.query.tableName.findFirst({
where: and(
eq(tableName.id, id),
eq(tableName.tenantId, session.user.tenantId)
),
});
if (!item) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
return NextResponse.json({ data: item });
} catch (error) {
console.error('[API] Error:', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
```
## Error Response Format
```typescript
// Standard error responses (FERPA-safe - no data leakage)
{ error: 'Unauthorized' } // 401 - Not authenticated
{ error: 'Forbidden' } // 403 - Wrong role
{ error: 'Not found' } // 404 - Doesn't exist or wrong tenant
{ error: 'Validation error', details: [...] } // 400 - Bad input
{ error: 'Internal server error' } // 500 - Something broke
// ❌ NEVER expose internal details
{ error: `Item ${id} not found in tenant ${tenantId}` } // WRONG!
```
## Role Hierarchy
| Role | Can Access |
| -------------- | -------------------------------- |
| student | Own data, joined assistants |
| teacher | Own assistants, class students |
| tenant_admin | All tenant data, user management |
| platform_admin | Everything (cross-tenant) |
## Checklist
- [ ] Session authentication
- [ ] Role-based authorization
- [ ] Tenant scoping on ALL queries
- [ ] Input validation with Zod
- [ ] Params awaited (Next.js 16)
- [ ] FERPA-safe error messages
- [ ] Audit logging for sensitive ops
- [ ] TypeScript types completeRelated Skills
custom-agent-creator
Skill to create custom agents for VS Code Copilot or OpenCode, helping users configure and generate agent files with proper formatting and configurations. Use when users want to create specialized AI assistants for VS Code Copilot (.agent.md files) or OpenCode (JSON/markdown agent configs) with specific tools, prompts, models, and behaviors. If the user is not specific about the target platform, ask them to specify Copilot or OpenCode.
agent-creator
This skill should be used when the user asks to "create a new agent", "make a subagent", "build an agent for X", "generate agent configuration", or wants to create a new Claude Code sub-agent. Triggers on "agent-creator", "new agent", "subagent", or agent creation requests.
add-route-context
为Flutter页面添加路由上下文记录功能,支持日期等参数的AI上下文识别。当需要让AI助手通过"询问当前上下文"功能获取页面状态(如日期、ID等参数)时使用。适用场景:(1) 日期驱动的页面(日记、活动、日历等),(2) ID驱动的页面(用户详情、订单详情等),(3) 任何需要AI理解当前页面参数的场景
voice-dna-creator
Analyze writing samples to create a comprehensive voice DNA profile. Use when the user wants to capture their unique writing voice, needs to create a voice profile for AI content, or is setting up a new writing system.
redbook-creator
Use this skill when the user wants to create Xiaohongshu (小红书/RedBook) posts. Trigger phrases: 小红书创作, create redbook, 小红书, 红书, 笔记创作, 帖子创作. The user will provide images, videos, or text content. This skill analyzes the content, searches for trending Xiaohongshu posts as reference, generates post title and copy, auto-edits videos (merge, subtitles, BGM, narration), attempts auto-upload to Xiaohongshu creator platform, and generates a local preview HTML file.
medium-posts-creator
Transform arbitrary text into well-structured Medium article drafts following a four-part structure: three variations of article title, Benefits from solution, Problem description, and Solution itself. Use when user requests: creating a Medium article from text, writing a blog post about a topic, transforming content into a Medium draft, or any request to transform text into a publishable article format. Includes Medium formatting guidelines, optional writing style suggestions, and enhancement tips for SEO, CTAs, and engagement.
obsidian-clipper-template-creator
Guide for creating templates for the Obsidian Web Clipper. Use when you want to create a new clipping template, understand available variables, or format clipped content.
instruction-creator
Create and manage high-quality custom instruction files for GitHub Copilot. Use when you need to define new project-specific guidelines, workflows, or coding standards in the instructions/ directory.
github-issue-creator
Convert raw notes, error logs, voice dictation, or screenshots into crisp GitHub-flavored markdown issue reports. Use when the user pastes bug info, error messages, or informal descriptions and wan...
Arcanea Creator Academy
The integration of Teacher Team with Arcanea's creator education mission
content-creator
Create SEO-optimized marketing content with consistent brand voice. Includes brand voice analyzer, SEO optimizer, content frameworks, and social media templates. Use when writing blog posts, creating social media content, analyzing brand voice, optimizing SEO, planning content calendars, or when user mentions content creation, brand voice, SEO optimization, social media marketing, or content strategy.
spring-boot-project-creator
Creates and scaffolds a new Spring Boot project (3.x or 4.x) by downloading from Spring Initializr, generating package structure (DDD or Layered architecture), configuring JPA, SpringDoc OpenAPI, and Docker Compose services (PostgreSQL, Redis, MongoDB). Use when creating a new Java Spring Boot project from scratch, bootstrapping a microservice, or initializing a backend application.