ワンクリックで
mandu-create-api
REST API 생성. CRUD/인증/업로드 엔드포인트. 'API', 'endpoint', 'CRUD' 시 자동 호출
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
REST API 생성. CRUD/인증/업로드 엔드포인트. 'API', 'endpoint', 'CRUD' 시 자동 호출
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Canonical Mandu agent workflow. Use first in Mandu projects before direct source edits so Codex, Claude Code, Gemini CLI, and other agents follow the same context -> plan -> apply -> verify -> repair loop.
React composition patterns for Mandu applications. Use when designing Island components, managing shared state, or building reusable component APIs. Triggers on compound components, context providers, boolean props, or component architecture tasks.
Production deployment patterns for Mandu applications
File-system based routing for Mandu. Use when creating pages, API routes, layouts, or dynamic routes. Triggers on tasks involving app/ folder, page.tsx, route.ts, layout.tsx, [id], [...slug], or URL patterns.
Architecture guard system for Mandu. Use when checking layer dependencies, enforcing architecture rules, or validating file locations. Triggers on tasks involving architecture, layers, dependencies, or guard commands.
Island Hydration pattern for Mandu. Use when creating interactive components, client-side state, or partial hydration. Triggers on tasks involving "use client", client.tsx, useState, useEffect, Island, or hydration.
| name | mandu-create-api |
| description | REST API 생성. CRUD/인증/업로드 엔드포인트. 'API', 'endpoint', 'CRUD' 시 자동 호출 |
REST API 엔드포인트를 생성하는 워크플로우. Route + Contract + Slot + Test 파이프라인으로 완전한 API를 스캐폴딩합니다.
// app/api/posts/route.ts
import { Mandu } from "@mandujs/core";
export default Mandu.filling()
.get((ctx) => ctx.ok({ posts: [] }))
.post(async (ctx) => {
const body = await ctx.body<CreatePostInput>();
return ctx.created({ post: body });
});
// src/shared/contracts/post.contract.ts
import { z } from "zod";
export const CreatePostInput = z.object({
title: z.string().min(1).max(200),
content: z.string().min(1),
tags: z.array(z.string()).optional(),
});
export const PostResponse = z.object({
id: z.string(),
title: z.string(),
content: z.string(),
createdAt: z.string().datetime(),
});
export type CreatePostInput = z.infer<typeof CreatePostInput>;
export type PostResponse = z.infer<typeof PostResponse>;
// spec/slots/posts.slot.ts
import { Mandu } from "@mandujs/core";
import { CreatePostInput } from "@/shared/contracts/post.contract";
export default Mandu.filling()
.guard(async (ctx) => {
const token = ctx.headers.get("authorization");
if (!token) return ctx.error(401, "Unauthorized");
ctx.set("userId", await verifyToken(token));
})
.post(async (ctx) => {
const body = await ctx.body<CreatePostInput>();
const validated = CreatePostInput.parse(body);
const post = await db.posts.create({ ...validated, userId: ctx.get("userId") });
return ctx.created({ post });
});
// tests/api/posts.test.ts
import { describe, test, expect } from "bun:test";
describe("POST /api/posts", () => {
test("creates a post with valid input", async () => {
const res = await fetch("http://localhost:3333/api/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer test-token",
},
body: JSON.stringify({ title: "Test", content: "Hello" }),
});
expect(res.status).toBe(201);
const data = await res.json();
expect(data.post.title).toBe("Test");
});
test("returns 401 without auth", async () => {
const res = await fetch("http://localhost:3333/api/posts", {
method: "POST",
body: JSON.stringify({ title: "Test", content: "Hello" }),
});
expect(res.status).toBe(401);
});
});
app/api/{resource}/route.ts GET (list), POST (create)
app/api/{resource}/[id]/route.ts GET (read), PATCH (update), DELETE (remove)
src/shared/contracts/{resource}.contract.ts
spec/slots/{resource}.slot.ts
tests/api/{resource}.test.ts
| Tool | Purpose |
|---|---|
mandu_add_route | Create route file at correct path |
mandu_create_contract | Generate Zod contract schema |
mandu_negotiate | Analyze API requirements |
mandu_generate | Full scaffold generation |
// Bearer token guard
.guard(async (ctx) => {
const token = ctx.headers.get("authorization")?.replace("Bearer ", "");
if (!token) return ctx.error(401, "Missing token");
ctx.set("user", await verifyToken(token));
})
// API key guard
.guard((ctx) => {
const key = ctx.headers.get("x-api-key");
if (key !== process.env.API_KEY) return ctx.error(403, "Invalid API key");
})
Mandu.filling() 체인으로 export.guard()로 인증/인가 처리 (인라인 체크 금지)ctx.error(status, message) 사용ctx.body()는 반드시 awaitmandu-mcp-create-flow — Track C (single route) 레시피로 이 워크플로우를 MCP 도구 순서로 정리mandu-mcp-verify — API 추가 직후 ate.auto_pipeline + guard_check 병렬 검증