用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/microwind/ai-skills --skill restful-api命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | RESTful API设计 |
| description | 当设计RESTful API时,分析资源模型,优化接口设计,解决性能问题。验证API架构,设计版本控制,和最佳实践。 |
| license | MIT |
RESTful API是现代Web服务的核心架构。不当的API设计会导致性能问题、安全漏洞和维护困难。需要系统化的API设计方法和规范。
核心原则: 好的RESTful API应该资源导向、状态清晰、版本可控、易于扩展。坏的RESTful API会导致接口混乱、性能下降、安全风险。
始终:
触发短语:
问题:
API端点命名不符合REST规范,导致接口混乱
错误示例:
- 使用动词而非名词: /getUser, /createUser
- 命名不一致: /users, /user_list
- 复数形式错误: /user, /userss
- 层级过深: /api/v1/users/1/posts/1/comments/1
解决方案:
1. 使用名词表示资源
2. 保持命名一致性
3. 使用正确的复数形式
4. 限制资源层级深度
问题:
不正确使用HTTP方法,违反REST原则
错误示例:
- GET用于创建资源
- POST用于查询操作
- PUT用于部分更新
- 所有操作都用POST
解决方案:
1. GET用于查询和获取
2. POST用于创建资源
3. PUT用于完整更新
4. PATCH用于部分更新
5. DELETE用于删除资源
问题:
HTTP状态码使用不规范,影响客户端处理
错误示例:
- 所有响应都返回200
- 错误时返回404而非400
- 成功时返回201而非200
- 缺少适当的错误信息
解决方案:
1. 200表示成功请求
2. 201表示资源创建成功
3. 400表示客户端错误
4. 404表示资源不存在
5. 500表示服务器错误
问题:
API缺少版本控制,导致升级困难
错误示例:
- 直接修改现有接口
- 强制客户端升级
- 不兼容的变更
- 缺少版本规划
解决方案:
1. 实施URL路径版本控制
2. 保持向后兼容性
3. 提前通知版本废弃
4. 制定版本迁移计划
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from datetime import datetime
from typing import Dict, Any, List, Optional
from dataclasses import dataclass
from enum import Enum
import uuid
import re
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///api.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class HTTPStatus(Enum):
"""HTTP状态码"""
OK = 200
CREATED = 201
NO_CONTENT = 204
BAD_REQUEST = 400
UNAUTHORIZED = 401
FORBIDDEN = 403
NOT_FOUND = 404
CONFLICT = 409
UNPROCESSABLE_ENTITY = 422
INTERNAL_SERVER_ERROR = 500
@dataclass
class APIResponse:
"""API响应格式"""
success: bool
data: Optional[Any] = None
error: Optional[str] = None
message: [] =
meta: [[, ]] =
():
():
.message = message
.field = field
().__init__(message)
():
():
.message = message
.status_code = status_code
().__init__(message)
(db.Model):
__abstract__ =
= db.Column(db.String(), primary_key=, default=: (uuid.uuid4()))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
():
__tablename__ =
name = db.Column(db.String(), nullable=)
email = db.Column(db.String(), unique=, nullable=)
password_hash = db.Column(db.String(), nullable=)
is_active = db.Column(db.Boolean, default=)
posts = db.relationship(, backref=, lazy=, cascade=)
():
{
: .,
: .name,
: .email,
: .is_active,
: .created_at.isoformat(),
: .updated_at.isoformat()
}
():
__tablename__ =
title = db.Column(db.String(), nullable=)
content = db.Column(db.Text, nullable=)
author_id = db.Column(db.String(), db.ForeignKey(), nullable=)
is_published = db.Column(db.Boolean, default=)
():
{
: .,
: .title,
: .content,
: .author_id,
: .is_published,
: .created_at.isoformat(),
: .updated_at.isoformat()
}
:
() -> :
pattern =
re.(pattern, email)
() -> [, ]:
errors = []
is_update data:
name = data.get(, ).strip()
name:
errors.append()
(name) < :
errors.append()
(name) > :
errors.append()
is_update data:
email = data.get(, ).strip()
email:
errors.append()
RequestValidator.validate_email(email):
errors.append()
errors:
ValidationError(.join(errors))
data
() -> [, ]:
errors = []
is_update data:
title = data.get(, ).strip()
title:
errors.append()
(title) < :
errors.append()
(title) > :
errors.append()
is_update data:
content = data.get(, ).strip()
content:
errors.append()
(content) < :
errors.append()
errors:
ValidationError(.join(errors))
data
:
() -> [, ]:
page = (, request.args.get(, , =))
limit = (, (, request.args.get(, , =)))
offset = (page - ) * limit
{: page, : limit, : offset}
() -> [, ]:
total_pages = (total + limit - ) // limit
{
: items,
: {
: page,
: limit,
: total,
: total_pages,
: page < total_pages,
: page >
}
}
:
() -> :
response = APIResponse(
success=error ,
data=data,
error=error,
message=message,
meta=meta
)
jsonify(response.__dict__), status_code
() -> :
.create_response(
error=error.message,
status_code=HTTPStatus.BAD_REQUEST.value
)
() -> :
.create_response(
error=,
status_code=HTTPStatus.NOT_FOUND.value
)
() -> :
.create_response(
error=message,
status_code=HTTPStatus.CONFLICT.value
)
() -> :
app.logger.error()
.create_response(
error=,
status_code=HTTPStatus.INTERNAL_SERVER_ERROR.value
)
():
():
.validator = RequestValidator()
():
:
pagination = PaginationHelper.get_pagination_params()
query = User.query
request.args:
search = request.args[]
query = query.(User.name.contains(search) | User.email.contains(search))
sort_by = request.args.get(, )
sort_order = request.args.get(, )
(User, sort_by):
sort_order == :
query = query.order_by((User, sort_by).desc())
:
query = query.order_by((User, sort_by).asc())
total = query.count()
users = query.offset(pagination[]).limit(pagination[]).()
result = PaginationHelper.create_pagination_response(
[user.to_dict() user users],
total,
pagination[],
pagination[]
)
.create_response(data=result)
Exception e:
.handle_server_error(e)
():
:
user = User.query.get(user_id)
user:
.handle_not_found()
.create_response(data=user.to_dict())
Exception e:
.handle_server_error(e)
():
:
data = request.get_json()
data:
.create_response(
error=,
status_code=HTTPStatus.BAD_REQUEST.value
)
validated_data = .validator.validate_user_data(data)
User.query.filter_by(email=validated_data[]).first():
.handle_conflict()
user = User(
name=validated_data[],
email=validated_data[],
password_hash=
)
db.session.add(user)
db.session.commit()
.create_response(
data=user.to_dict(),
message=,
status_code=HTTPStatus.CREATED.value
)
ValidationError e:
.handle_validation_error(e)
Exception e:
db.session.rollback()
.handle_server_error(e)
():
:
user = User.query.get(user_id)
user:
.handle_not_found()
data = request.get_json()
data:
.create_response(
error=,
status_code=HTTPStatus.BAD_REQUEST.value
)
validated_data = .validator.validate_user_data(data, is_update=)
validated_data:
existing_user = User.query.(
User.email == validated_data[],
User. != user_id
).first()
existing_user:
.handle_conflict()
key, value validated_data.items():
(user, key):
(user, key, value)
user.updated_at = datetime.utcnow()
db.session.commit()
.create_response(
data=user.to_dict(),
message=
)
ValidationError e:
.handle_validation_error(e)
Exception e:
db.session.rollback()
.handle_server_error(e)
():
:
user = User.query.get(user_id)
user:
.handle_not_found()
db.session.delete(user)
db.session.commit()
.create_response(
data={: user.to_dict()},
message=,
status_code=HTTPStatus.NO_CONTENT.value
)
Exception e:
db.session.rollback()
.handle_server_error(e)
():
():
.validator = RequestValidator()
():
:
pagination = PaginationHelper.get_pagination_params()
query = Post.query
request.args:
query = query.(Post.author_id == request.args[])
request.args:
query = query.(Post.is_published == request.args[].lower() == )
request.args:
search = request.args[]
query = query.(Post.title.contains(search) | Post.content.contains(search))
sort_by = request.args.get(, )
sort_order = request.args.get(, )
(Post, sort_by):
sort_order == :
query = query.order_by((Post, sort_by).desc())
:
query = query.order_by((Post, sort_by).asc())
total = query.count()
posts = query.offset(pagination[]).limit(pagination[]).()
result = PaginationHelper.create_pagination_response(
[post.to_dict() post posts],
total,
pagination[],
pagination[]
)
.create_response(data=result)
Exception e:
.handle_server_error(e)
():
:
post = Post.query.get(post_id)
post:
.handle_not_found()
.create_response(data=post.to_dict())
Exception e:
.handle_server_error(e)
():
:
data = request.get_json()
data:
.create_response(
error=,
status_code=HTTPStatus.BAD_REQUEST.value
)
validated_data = .validator.validate_post_data(data)
author_id = validated_data.get()
User.query.get(author_id):
.handle_not_found()
post = Post(
title=validated_data[],
content=validated_data[],
author_id=author_id,
is_published=validated_data.get(, )
)
db.session.add(post)
db.session.commit()
.create_response(
data=post.to_dict(),
message=,
status_code=HTTPStatus.CREATED.value
)
ValidationError e:
.handle_validation_error(e)
Exception e:
db.session.rollback()
.handle_server_error(e)
user_controller = UserController()
post_controller = PostController()
():
user_controller.get_users()
():
user_controller.create_user()
():
user_controller.get_user(user_id)
():
user_controller.update_user(user_id)
():
user_controller.delete_user(user_id)
():
post_controller.get_posts()
():
post_controller.create_post()
():
post_controller.get_post(post_id)
():
APIController().create_response(
error=,
status_code=HTTPStatus.NOT_FOUND.value
)
():
APIController().create_response(
error=,
status_code=
)
():
APIController().handle_server_error(error)
():
()
app.app_context():
db.create_all()
()
()
()
()
()
()
()
()
()
()
()
()
()
__name__ == :
main()
app.run(debug=)
from typing import Dict, Any, List, Optional
from dataclasses import dataclass
from enum import Enum
import json
from datetime import datetime
class HTTPMethod(Enum):
"""HTTP方法"""
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
PATCH = "PATCH"
class ParameterType(Enum):
"""参数类型"""
STRING = "string"
INTEGER = "integer"
BOOLEAN = "boolean"
ARRAY = "array"
OBJECT = "object"
@dataclass
class APIParameter:
"""API参数"""
name: str
type: ParameterType
required: bool = False
description: str = ""
default_value: Any = None
example: Any = None
@dataclass
class APIResponse:
"""API响应"""
status_code: int
description: str
schema: [[, ]] =
example: [[, ]] =
:
path:
method: HTTPMethod
summary:
description:
parameters: [APIParameter]
responses: [APIResponse]
tags: []
:
():
.endpoints: [APIEndpoint] = []
.schemas: [, [, ]] = {}
.info = {
: ,
: ,
:
}
():
.endpoints.append(endpoint)
():
.schemas[name] = schema
() -> [, ]:
spec = {
: ,
: .info,
: {},
: {
: .schemas
}
}
paths = {}
endpoint .endpoints:
endpoint.path paths:
paths[endpoint.path] = {}
operation = {
: endpoint.summary,
: endpoint.description,
: endpoint.tags,
: [],
: {}
}
param endpoint.parameters:
param_spec = {
: param.name,
: endpoint.method [HTTPMethod.GET] ,
: param.required,
: {
: param..value
}
}
param.description:
param_spec[] = param.description
param.default_value :
param_spec[][] = param.default_value
param.example :
param_spec[] = param.example
operation[].append(param_spec)
response endpoint.responses:
response_spec = {
: response.description
}
response.schema:
response_spec[] = {
: {
: response.schema
}
}
response.example:
response_spec:
response_spec[] = {: {}}
response_spec[][][] = response.example
operation[][(response.status_code)] = response_spec
paths[endpoint.path][endpoint.method.value.lower()] = operation
spec[] = paths
spec
() -> :
lines = [
,
,
.info[],
,
,
,
]
tags = ()
endpoint .endpoints:
tags.update(endpoint.tags)
tag (tags):
lines.append()
lines.extend([, , ])
tag (tags):
lines.append()
lines.append()
tag_endpoints = [ep ep .endpoints tag ep.tags]
endpoint tag_endpoints:
lines.extend([
,
,
,
])
endpoint.parameters:
lines.append()
param endpoint.parameters:
required_str = param.required
lines.append()
param.description:
lines.append()
param.default_value :
lines.append()
lines.append()
lines.append()
response endpoint.responses:
lines.append()
lines.append()
lines.append()
lines.append()
.join(lines)
():
()
doc_gen = APIDocumentationGenerator()
user_schema = {
: ,
: {
: {: , : },
: {: , : , : },
: {: , : },
: {: },
: {: , : }
},
: [, ]
}
doc_gen.add_schema(, user_schema)
get_users_endpoint = APIEndpoint(
path=,
method=HTTPMethod.GET,
summary=,
description=,
parameters=[
APIParameter(, ParameterType.INTEGER, , , , ),
APIParameter(, ParameterType.INTEGER, , , , ),
APIParameter(, ParameterType.STRING, , ),
APIParameter(, ParameterType.STRING, , , ),
APIParameter(, ParameterType.STRING, , , )
],
responses=[
APIResponse(, , {: {: , : {: }}}),
APIResponse(, ),
APIResponse(, )
],
tags=[]
)
create_user_endpoint = APIEndpoint(
path=,
method=HTTPMethod.POST,
summary=,
description=,
parameters=[
APIParameter(, ParameterType.STRING, , , example=),
APIParameter(, ParameterType.STRING, , , example=),
APIParameter(, ParameterType.STRING, , )
],
responses=[
APIResponse(, , {: }),
APIResponse(, ),
APIResponse(, ),
APIResponse(, )
],
tags=[]
)
doc_gen.add_endpoint(get_users_endpoint)
doc_gen.add_endpoint(create_user_endpoint)
openapi_spec = doc_gen.generate_openapi_spec()
()
(json.dumps(openapi_spec, indent=, ensure_ascii=))
markdown_docs = doc_gen.generate_markdown_docs()
()
(markdown_docs[:] + (markdown_docs) > markdown_docs)
__name__ == :
main()
/api/v1/usersAccept: application/vnd.api+json;version=1?version=1