api-documenting
Generate API documentation from code. Use when the user wants to document APIs, create API reference, generate endpoint documentation, or needs help with OpenAPI/Swagger specs.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install huangjia2019-claude-code-engineering-02-progressive-skill
Repository
Skill path: 04-Skills/projects/02-progressive-skill
Generate API documentation from code. Use when the user wants to document APIs, create API reference, generate endpoint documentation, or needs help with OpenAPI/Swagger specs.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack, Backend.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: huangjia2019.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install api-documenting into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/huangjia2019/claude-code-engineering before adding api-documenting to shared team environments
- Use api-documenting for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: api-documenting
description: Generate API documentation from code. Use when the user wants to document APIs, create API reference, generate endpoint documentation, or needs help with OpenAPI/Swagger specs.
allowed-tools:
- Read
- Grep
- Glob
- Write
---
# API Documentation Generator
Generate comprehensive API documentation from source code.
## Quick Reference
For common documentation patterns, see `PATTERNS.md`.
## Documentation Standards
See `STANDARDS.md` for our documentation conventions.
## Process
### Step 1: Identify API Endpoints
Look for:
- Route definitions (Express, FastAPI, etc.)
- Controller methods
- Handler functions
### Step 2: Extract Information
For each endpoint, extract:
- HTTP method (GET, POST, PUT, DELETE, etc.)
- Path/route
- Parameters (path, query, body)
- Request/response schemas
- Authentication requirements
### Step 3: Generate Documentation
Use the template in `templates/endpoint.md` for consistent formatting.
### Step 4: Create Overview
Generate an index of all endpoints with the template in `templates/index.md`.
## Output Formats
### Markdown (Default)
Generate markdown documentation suitable for README or docs site.
### OpenAPI/Swagger
If requested, generate OpenAPI 3.0 spec. See `templates/openapi.yaml` for structure.
## Examples
See `EXAMPLES.md` for sample inputs and outputs.
## Scripts
To auto-detect routes in common frameworks:
```bash
python scripts/detect_routes.py <source_directory>
```
To validate generated OpenAPI spec:
```bash
./scripts/validate_openapi.sh <spec_file>
```
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### scripts/detect_routes.py
```python
#!/usr/bin/env python3
"""
Route Detection Script
Automatically detects API routes in common web frameworks.
Supports: Express.js, FastAPI, Flask, Spring Boot, Go (Gin/Echo)
Usage:
python detect_routes.py <source_directory>
Output:
JSON list of detected routes with metadata
"""
import os
import re
import sys
import json
from pathlib import Path
# Route patterns for different frameworks
PATTERNS = {
'express': [
# app.get('/path', handler)
r"app\.(get|post|put|delete|patch)\s*\(\s*['\"]([^'\"]+)['\"]",
# router.get('/path', handler)
r"router\.(get|post|put|delete|patch)\s*\(\s*['\"]([^'\"]+)['\"]",
],
'fastapi': [
# @app.get("/path")
r"@app\.(get|post|put|delete|patch)\s*\(\s*['\"]([^'\"]+)['\"]",
# @router.get("/path")
r"@router\.(get|post|put|delete|patch)\s*\(\s*['\"]([^'\"]+)['\"]",
],
'flask': [
# @app.route('/path', methods=['GET'])
r"@app\.route\s*\(\s*['\"]([^'\"]+)['\"].*?methods\s*=\s*\[([^\]]+)\]",
# @blueprint.route('/path')
r"@\w+\.route\s*\(\s*['\"]([^'\"]+)['\"]",
],
'spring': [
# @GetMapping("/path")
r"@(Get|Post|Put|Delete|Patch)Mapping\s*\(\s*['\"]?([^'\")\s]+)",
# @RequestMapping(value="/path", method=...)
r"@RequestMapping\s*\([^)]*value\s*=\s*['\"]([^'\"]+)['\"]",
],
'go_gin': [
# r.GET("/path", handler)
r"\w+\.(GET|POST|PUT|DELETE|PATCH)\s*\(\s*['\"]([^'\"]+)['\"]",
],
}
def detect_framework(content: str) -> str:
"""Detect which framework is being used based on imports/requires."""
if 'express' in content.lower() or "require('express')" in content:
return 'express'
elif 'fastapi' in content.lower() or 'from fastapi' in content:
return 'fastapi'
elif 'flask' in content.lower() or 'from flask' in content:
return 'flask'
elif '@RestController' in content or '@RequestMapping' in content:
return 'spring'
elif 'gin.Default()' in content or 'echo.New()' in content:
return 'go_gin'
return None
def extract_routes(file_path: Path) -> list:
"""Extract routes from a single file."""
routes = []
try:
content = file_path.read_text()
except Exception as e:
print(f"Warning: Could not read {file_path}: {e}", file=sys.stderr)
return routes
framework = detect_framework(content)
if not framework:
return routes
patterns = PATTERNS.get(framework, [])
for pattern in patterns:
matches = re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE)
for match in matches:
groups = match.groups()
if len(groups) >= 2:
method = groups[0].upper()
path = groups[1]
else:
method = 'GET' # Default
path = groups[0]
routes.append({
'method': method,
'path': path,
'file': str(file_path),
'line': content[:match.start()].count('\n') + 1,
'framework': framework,
})
return routes
def scan_directory(directory: str) -> list:
"""Scan a directory for route definitions."""
all_routes = []
# File extensions to scan
extensions = {'.js', '.ts', '.py', '.java', '.go', '.kt'}
path = Path(directory)
if not path.exists():
print(f"Error: Directory {directory} does not exist", file=sys.stderr)
sys.exit(1)
for file_path in path.rglob('*'):
if file_path.suffix in extensions and file_path.is_file():
# Skip node_modules, venv, etc.
if any(skip in str(file_path) for skip in ['node_modules', 'venv', '.git', 'dist', 'build']):
continue
routes = extract_routes(file_path)
all_routes.extend(routes)
return all_routes
def main():
if len(sys.argv) < 2:
print("Usage: python detect_routes.py <source_directory>", file=sys.stderr)
sys.exit(1)
directory = sys.argv[1]
routes = scan_directory(directory)
# Sort by path for readability
routes.sort(key=lambda r: (r['path'], r['method']))
# Output as JSON
print(json.dumps(routes, indent=2))
# Summary to stderr
print(f"\nFound {len(routes)} routes in {directory}", file=sys.stderr)
if __name__ == '__main__':
main()
```
### scripts/validate_openapi.sh
```bash
#!/bin/bash
# OpenAPI Specification Validator
#
# Validates an OpenAPI spec file for correctness.
# Requires: npx (Node.js) or swagger-cli
#
# Usage:
# ./validate_openapi.sh <spec_file>
#
# Example:
# ./validate_openapi.sh api-spec.yaml
set -e
SPEC_FILE="$1"
if [ -z "$SPEC_FILE" ]; then
echo "Usage: $0 <spec_file>"
echo "Example: $0 api-spec.yaml"
exit 1
fi
if [ ! -f "$SPEC_FILE" ]; then
echo "Error: File '$SPEC_FILE' not found"
exit 1
fi
echo "Validating OpenAPI spec: $SPEC_FILE"
echo "=================================="
# Check if swagger-cli is available
if command -v swagger-cli &> /dev/null; then
echo "Using swagger-cli..."
swagger-cli validate "$SPEC_FILE"
# Check if npx is available (Node.js)
elif command -v npx &> /dev/null; then
echo "Using @apidevtools/swagger-cli via npx..."
npx @apidevtools/swagger-cli validate "$SPEC_FILE"
# Check if Python spectral is available
elif command -v spectral &> /dev/null; then
echo "Using Spectral..."
spectral lint "$SPEC_FILE"
else
echo "Warning: No OpenAPI validator found."
echo "Install one of:"
echo " - npm install -g @apidevtools/swagger-cli"
echo " - npm install -g @stoplight/spectral-cli"
echo ""
echo "Performing basic YAML syntax check instead..."
# Basic YAML check
if command -v python3 &> /dev/null; then
python3 -c "import yaml; yaml.safe_load(open('$SPEC_FILE'))" && echo "YAML syntax: OK"
elif command -v ruby &> /dev/null; then
ruby -ryaml -e "YAML.load_file('$SPEC_FILE')" && echo "YAML syntax: OK"
else
echo "Cannot perform YAML check without Python or Ruby"
exit 1
fi
fi
echo ""
echo "Validation complete!"
```
### templates/endpoint.md
```markdown
# Endpoint Documentation Template
Use this template for each API endpoint:
```markdown
## {METHOD} {PATH}
{Brief description of what this endpoint does.}
### Authentication
{Required | Optional | None}
### Parameters
| Name | Location | Type | Required | Description |
|------|----------|------|----------|-------------|
| {name} | {path/query/header/body} | {type} | {Yes/No} | {description} |
### Request Body
{If applicable}
```json
{
"field": "value"
}
```
### Responses
#### {Status Code} {Status Text}
{Description of when this response occurs}
```json
{
"example": "response"
}
```
### Example
**Request**:
```bash
curl -X {METHOD} '{BASE_URL}{PATH}' \
-H 'Content-Type: application/json' \
-d '{request_body}'
```
**Response**:
```json
{
"example": "response"
}
```
### Notes
{Any additional information, caveats, or related endpoints}
```
```
### templates/index.md
```markdown
# API Index Template
Use this template for the API overview page:
```markdown
# {API Name} API Reference
{Brief description of the API}
## Base URL
`{BASE_URL}`
## Authentication
{Description of authentication methods}
## Endpoints
### {Resource Group 1}
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /resource | List all resources |
| POST | /resource | Create a resource |
| GET | /resource/:id | Get a specific resource |
| PUT | /resource/:id | Update a resource |
| DELETE | /resource/:id | Delete a resource |
### {Resource Group 2}
| Method | Endpoint | Description |
|--------|----------|-------------|
| ... | ... | ... |
## Common Response Codes
| Code | Description |
|------|-------------|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 500 | Internal Server Error |
## Rate Limiting
{Rate limiting information if applicable}
## Versioning
{API versioning strategy}
```
```
### templates/openapi.yaml
```yaml
# OpenAPI Template
# Use this as a starting point for generating OpenAPI specs
openapi: 3.0.0
info:
title: API Title
description: API description goes here
version: 1.0.0
contact:
name: API Support
email: [email protected]
servers:
- url: https://api.example.com/v1
description: Production server
- url: https://staging-api.example.com/v1
description: Staging server
paths:
/example:
get:
summary: Example endpoint
description: Detailed description of what this endpoint does
operationId: getExample
tags:
- Examples
parameters:
- name: id
in: query
required: false
schema:
type: string
description: Filter by ID
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Example'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Example:
type: object
required:
- id
- name
properties:
id:
type: string
description: Unique identifier
name:
type: string
description: Resource name
createdAt:
type: string
format: date-time
description: Creation timestamp
Error:
type: object
required:
- code
- message
properties:
code:
type: string
description: Error code
message:
type: string
description: Error message
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
tags:
- name: Examples
description: Example endpoints
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### EXAMPLES.md
```markdown
# API Documentation Examples
## Example 1: Simple Express.js Endpoint
### Input Code
```javascript
// routes/users.js
router.get('/users/:id', async (req, res) => {
const { id } = req.params;
const user = await User.findById(id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
```
### Generated Documentation
```markdown
## GET /users/:id
Retrieve a user by their unique identifier.
### Parameters
| Name | Location | Type | Required | Description |
|------|----------|------|----------|-------------|
| id | path | string | Yes | The unique identifier of the user |
### Responses
#### 200 OK
Returns the user object.
```json
{
"id": "123",
"name": "John Doe",
"email": "[email protected]",
"createdAt": "2024-01-15T10:30:00Z"
}
```
#### 404 Not Found
User with specified ID does not exist.
```json
{
"error": "User not found"
}
```
```
---
## Example 2: FastAPI with Pydantic
### Input Code
```python
from pydantic import BaseModel
from fastapi import FastAPI, HTTPException
class UserCreate(BaseModel):
name: str
email: str
password: str
class UserResponse(BaseModel):
id: str
name: str
email: str
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
"""Create a new user account."""
# ... implementation
return new_user
```
### Generated Documentation
```markdown
## POST /users
Create a new user account.
### Request Body
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| name | string | Yes | User's display name |
| email | string | Yes | User's email address |
| password | string | Yes | User's password |
**Example**:
```json
{
"name": "Jane Smith",
"email": "[email protected]",
"password": "securePassword123"
}
```
### Responses
#### 201 Created
User successfully created.
```json
{
"id": "456",
"name": "Jane Smith",
"email": "[email protected]"
}
```
```
---
## Example 3: OpenAPI Spec Output
### Generated OpenAPI YAML
```yaml
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users/{id}:
get:
summary: Get user by ID
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: User not found
components:
schemas:
User:
type: object
properties:
id:
type: string
name:
type: string
email:
type: string
```
```
### README.md
```markdown
# 示例项目:渐进式披露 Skill
这个项目展示完整的 Skill 结构,演示渐进式披露(Progressive Disclosure)模式。
## 目录结构
```
02-progressive-skill/
├── SKILL.md # 主指令文件(入口点)
├── PATTERNS.md # 框架路由模式参考
├── STANDARDS.md # 文档标准规范
├── EXAMPLES.md # 使用示例
├── templates/ # 文档模板
│ ├── endpoint.md # 单个端点模板
│ ├── index.md # API 索引模板
│ └── openapi.yaml # OpenAPI 规范模板
└── scripts/ # 辅助脚本
├── detect_routes.py # 自动检测路由
└── validate_openapi.sh # 验证 OpenAPI 规范
```
## Skill 说明
这是一个 API 文档生成 Skill。当用户需要为代码生成 API 文档时,Claude 会:
1. 首先加载 `SKILL.md`(主指令)
2. 根据需要加载其他文件(如模式、标准、模板)
3. 可以执行脚本来辅助工作
## 渐进式披露演示
### 场景 1:简单请求
用户:"帮我生成 API 文档"
Claude 加载:
- `SKILL.md` ✓
- 其他文件暂不加载
### 场景 2:需要模式参考
用户:"这是 Express.js 项目,帮我提取路由"
Claude 加载:
- `SKILL.md` ✓
- `PATTERNS.md` ✓(因为涉及框架特定模式)
### 场景 3:需要生成 OpenAPI
用户:"生成 OpenAPI 规范"
Claude 加载:
- `SKILL.md` ✓
- `templates/openapi.yaml` ✓(需要模板结构)
- `STANDARDS.md` ✓(确保符合标准)
### Token 消耗对比
| 场景 | 传统方式 | 渐进式披露 |
|------|----------|-----------|
| 简单请求 | ~3000 tokens | ~800 tokens |
| 框架特定 | ~3000 tokens | ~1200 tokens |
| 完整生成 | ~3000 tokens | ~2000 tokens |
## 关键学习点
### 1. SKILL.md 保持简洁
主文件只包含:
- 高层流程
- 文件引用(告诉 Claude 去哪找详细信息)
- 基本指令
详细内容放在引用文件中。
### 2. 有意义的文件名
```
PATTERNS.md # 清楚表示"模式"
STANDARDS.md # 清楚表示"标准"
EXAMPLES.md # 清楚表示"示例"
```
Claude 通过文件名快速判断需要哪个文件。
### 3. 脚本封装复杂逻辑
```bash
# 不需要 Claude 理解每行代码
python scripts/detect_routes.py <directory>
```
Claude 可以执行脚本而不需要将整个脚本内容放入上下文。
### 4. 模板提供一致性
`templates/` 目录包含标准化模板,确保输出格式一致。
## 测试方法
尝试以下请求观察 Claude 的行为:
1. "帮我为 src/api 目录生成 API 文档"
2. "这是 FastAPI 项目,提取所有路由"
3. "生成 OpenAPI 3.0 规范"
4. "按照团队标准格式化这个端点文档"
观察 Claude 会加载哪些文件。
## 扩展建议
可以添加更多内容:
- `reference/` 目录:详细的 API 参考
- `validation/` 目录:验证规则
- 更多框架支持的 pattern 文件
```