api-endpoint-generator
Generates CRUD REST API endpoints with request validation, TypeScript types, consistent response formats, error handling, and documentation. Includes route handlers, validation schemas (Zod/Joi), typed responses, and usage examples. Use when building "REST API", "CRUD endpoints", "API routes", or "backend endpoints".
Best use case
api-endpoint-generator is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Generates CRUD REST API endpoints with request validation, TypeScript types, consistent response formats, error handling, and documentation. Includes route handlers, validation schemas (Zod/Joi), typed responses, and usage examples. Use when building "REST API", "CRUD endpoints", "API routes", or "backend endpoints".
Teams using api-endpoint-generator 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-endpoint-generator/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How api-endpoint-generator Compares
| Feature / Agent | api-endpoint-generator | 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?
Generates CRUD REST API endpoints with request validation, TypeScript types, consistent response formats, error handling, and documentation. Includes route handlers, validation schemas (Zod/Joi), typed responses, and usage examples. Use when building "REST API", "CRUD endpoints", "API routes", or "backend 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 Endpoint Generator
Generate production-ready CRUD API endpoints with validation and type safety.
## Core Workflow
1. **Define resource**: Entity name and schema
2. **Generate routes**: POST, GET, PUT/PATCH, DELETE endpoints
3. **Add validation**: Request body/query validation with Zod/Joi
4. **Type responses**: TypeScript interfaces for all responses
5. **Error handling**: Consistent error responses
6. **Documentation**: OpenAPI/Swagger specs
7. **Examples**: Request/response samples
## Express + TypeScript Pattern
```typescript
// types/user.types.ts
export interface User {
id: string;
email: string;
name: string;
role: "user" | "admin";
createdAt: Date;
updatedAt: Date;
}
export interface CreateUserDto {
email: string;
name: string;
password: string;
}
export interface UpdateUserDto {
name?: string;
email?: string;
}
export interface ApiResponse<T> {
success: boolean;
data?: T;
error?: ApiError;
meta?: PaginationMeta;
}
export interface ApiError {
code: string;
message: string;
details?: Record<string, string[]>;
}
```
## Validation Schemas (Zod)
```typescript
// schemas/user.schema.ts
import { z } from "zod";
export const createUserSchema = z.object({
email: z.string().email("Invalid email address"),
name: z.string().min(2, "Name must be at least 2 characters"),
password: z
.string()
.min(8, "Password must be at least 8 characters")
.regex(/[A-Z]/, "Password must contain uppercase letter")
.regex(/[0-9]/, "Password must contain number"),
});
export const updateUserSchema = z
.object({
name: z.string().min(2).optional(),
email: z.string().email().optional(),
})
.refine((data) => Object.keys(data).length > 0, {
message: "At least one field must be provided",
});
export const getUsersQuerySchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().min(1).max(100).default(10),
sortBy: z.enum(["name", "email", "createdAt"]).optional(),
sortOrder: z.enum(["asc", "desc"]).default("desc"),
search: z.string().optional(),
});
export type CreateUserDto = z.infer<typeof createUserSchema>;
export type UpdateUserDto = z.infer<typeof updateUserSchema>;
export type GetUsersQuery = z.infer<typeof getUsersQuerySchema>;
```
## CRUD Route Handlers
```typescript
// routes/users.routes.ts
import { Router } from "express";
import { UserController } from "../controllers/user.controller";
import { validateRequest } from "../middleware/validate";
import { authenticate } from "../middleware/auth";
import {
createUserSchema,
updateUserSchema,
getUsersQuerySchema,
} from "../schemas/user.schema";
const router = Router();
const controller = new UserController();
// Create
router.post(
"/",
authenticate,
validateRequest({ body: createUserSchema }),
controller.create
);
// Read (list)
router.get(
"/",
authenticate,
validateRequest({ query: getUsersQuerySchema }),
controller.list
);
// Read (single)
router.get("/:id", authenticate, controller.getById);
// Update
router.patch(
"/:id",
authenticate,
validateRequest({ body: updateUserSchema }),
controller.update
);
// Delete
router.delete("/:id", authenticate, controller.delete);
export default router;
```
## Controller Implementation
```typescript
// controllers/user.controller.ts
import { Request, Response, NextFunction } from "express";
import { UserService } from "../services/user.service";
import {
CreateUserDto,
UpdateUserDto,
GetUsersQuery,
} from "../types/user.types";
import { ApiResponse } from "../types/api.types";
export class UserController {
private service = new UserService();
create = async (
req: Request<{}, {}, CreateUserDto>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.create(req.body);
res.status(201).json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
list = async (
req: Request<{}, {}, {}, GetUsersQuery>,
res: Response<ApiResponse<User[]>>,
next: NextFunction
) => {
try {
const { page, limit, sortBy, sortOrder, search } = req.query;
const result = await this.service.findAll({
page,
limit,
sortBy,
sortOrder,
search,
});
res.json({
success: true,
data: result.users,
meta: {
page: result.page,
limit: result.limit,
total: result.total,
totalPages: result.totalPages,
},
});
} catch (error) {
next(error);
}
};
getById = async (
req: Request<{ id: string }>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.findById(req.params.id);
if (!user) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "User not found",
},
});
}
res.json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
update = async (
req: Request<{ id: string }, {}, UpdateUserDto>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.update(req.params.id, req.body);
if (!user) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "User not found",
},
});
}
res.json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
delete = async (
req: Request<{ id: string }>,
res: Response<ApiResponse<void>>,
next: NextFunction
) => {
try {
const deleted = await this.service.delete(req.params.id);
if (!deleted) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "User not found",
},
});
}
res.status(204).send();
} catch (error) {
next(error);
}
};
}
```
## Validation Middleware
```typescript
// middleware/validate.ts
import { Request, Response, NextFunction } from "express";
import { ZodSchema } from "zod";
interface ValidationSchemas {
body?: ZodSchema;
query?: ZodSchema;
params?: ZodSchema;
}
export const validateRequest = (schemas: ValidationSchemas) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
if (schemas.body) {
req.body = schemas.body.parse(req.body);
}
if (schemas.query) {
req.query = schemas.query.parse(req.query);
}
if (schemas.params) {
req.params = schemas.params.parse(req.params);
}
next();
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
success: false,
error: {
code: "VALIDATION_ERROR",
message: "Invalid request data",
details: error.flatten().fieldErrors,
},
});
}
next(error);
}
};
};
```
## NestJS Pattern
```typescript
// users/users.controller.ts
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
} from "@nestjs/common";
import { ApiTags, ApiOperation, ApiResponse } from "@nestjs/swagger";
import { UsersService } from "./users.service";
import { CreateUserDto, UpdateUserDto, GetUsersQueryDto } from "./dto";
@ApiTags("users")
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@ApiOperation({ summary: "Create user" })
@ApiResponse({ status: 201, description: "User created" })
@ApiResponse({ status: 400, description: "Validation error" })
async create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Get()
@ApiOperation({ summary: "List users" })
async findAll(@Query() query: GetUsersQueryDto) {
return this.usersService.findAll(query);
}
@Get(":id")
@ApiOperation({ summary: "Get user by ID" })
async findOne(@Param("id") id: string) {
return this.usersService.findOne(id);
}
@Put(":id")
@ApiOperation({ summary: "Update user" })
async update(@Param("id") id: string, @Body() dto: UpdateUserDto) {
return this.usersService.update(id, dto);
}
@Delete(":id")
@ApiOperation({ summary: "Delete user" })
async remove(@Param("id") id: string) {
return this.usersService.remove(id);
}
}
```
## FastAPI Pattern (Python)
```python
# routers/users.py
from fastapi import APIRouter, Depends, HTTPException, Query
from typing import List, Optional
from pydantic import BaseModel, EmailStr, Field
router = APIRouter(prefix="/users", tags=["users"])
class CreateUserDto(BaseModel):
email: EmailStr
name: str = Field(..., min_length=2)
password: str = Field(..., min_length=8)
class UserResponse(BaseModel):
id: str
email: str
name: str
role: str
created_at: datetime
class PaginatedResponse(BaseModel):
data: List[UserResponse]
total: int
page: int
limit: int
@router.post("/", status_code=201, response_model=UserResponse)
async def create_user(dto: CreateUserDto, service: UserService = Depends()):
return await service.create(dto)
@router.get("/", response_model=PaginatedResponse)
async def list_users(
page: int = Query(1, ge=1),
limit: int = Query(10, ge=1, le=100),
search: Optional[str] = None,
service: UserService = Depends()
):
return await service.find_all(page, limit, search)
```
## Response Format Standards
```typescript
// Success Response
{
"success": true,
"data": { ... },
"meta": {
"page": 1,
"limit": 10,
"total": 50,
"totalPages": 5
}
}
// Error Response
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": {
"email": ["Invalid email address"],
"password": ["Password must contain uppercase letter"]
}
}
}
```
## Status Codes
- 200: Success (GET, PUT)
- 201: Created (POST)
- 204: No Content (DELETE)
- 400: Validation Error
- 401: Unauthorized
- 403: Forbidden
- 404: Not Found
- 409: Conflict
- 500: Server Error
## Best Practices
1. **Type everything**: Request, response, DTOs, errors
2. **Validate early**: Before hitting service layer
3. **Consistent responses**: Same structure everywhere
4. **HTTP semantics**: Use correct status codes
5. **Error details**: Include validation errors
6. **Pagination**: Always paginate lists
7. **Filtering/sorting**: Support common queries
8. **Documentation**: OpenAPI/Swagger specs
## Output Checklist
- [ ] Route definitions with HTTP methods
- [ ] Request validation schemas
- [ ] TypeScript types for all DTOs
- [ ] Controller handlers with error handling
- [ ] Consistent response format
- [ ] Pagination for list endpoints
- [ ] HTTP status codes correctly used
- [ ] Error response format
- [ ] OpenAPI/Swagger documentation
- [ ] Usage examples with curl/requestsRelated Skills
generator
Générateur de Skill - Crée de nouveaux fichiers SKILL.md depuis les définitions YAML d'agents
EchoKit Config Generator
Generate config.toml for EchoKit servers with interactive setup for ASR, TTS, LLM services, MCP servers, API key entry, and server launch
bigconfig-generator
Use this skill when creating or updating Bigeye monitoring configurations (bigconfig.yml files) for BigQuery tables. Works with metadata-manager skill.
ai-image-generator
使用 ModelScope 等平台生成 AI 图像。当用户需要生成图像、设计图标、创建角色立绘,或需要帮助编写 AI 绘画提示词时使用此技能。支持直接生成图像和仅优化提示词两种模式。
thumbnail-generator
Generate prompts for dev.to blog thumbnail/cover images in hand-drawn infographic style. Use when creating cover images, thumbnails, or featured images for blog posts. Recommended size 1000x420 pixels.
seedream-image-generator
Generate images using the Doubao SeeDream API based on text prompts. Use this skill when users request AI-generated images, artwork, illustrations, or visual content creation. The skill handles API calls, downloads generated images to the project's /pic folder, and supports batch generation of up to 4 sequential images.
og-image-generator
Generate and optimize Open Graph meta images for social media sharing. Use this skill when building web applications that need dynamic OG image generation with support for Vercel's @vercel/og library, pre-generated image storage, and social media optimization (Twitter Cards, Facebook, LinkedIn). Handles dynamic routes, performance optimization, and includes best practices for crawler compatibility and testing.
gemini-image-generator
Generate and edit images using Google Gemini. Use when the user asks to generate, create, edit, or modify images.
didactic-content-generator
Gere conteúdo didático de alta qualidade em HTML/CSS com ilustrações SVG, usando um sistema de Temas pré definidos e reutilizáveis. Capaz de criar ou editar apostilas, tutoriais e materiais educacionais que seguem filosofias pedagógicas claras.
article-image-generator
Generates consistent, professional cover images for business/fiscal articles using Ideogram with standardized prompts and naming conventions. Use when creating new articles, updating missing covers, or maintaining visual consistency across the content library.
apex-video-generator
Generate real estate marketing videos from property data. Use when creating property showcases, social media content, market reports, or neighborhood tours. Integrates Firecrawl scraped data with Remotion rendering.
pr-description-generator
Auto-activates when user mentions creating pull request, PR description, or merge request. Generates comprehensive PR descriptions from git diff and commit history.