场景
写接口时,参数校验代码又臭又长:判断必填、判断类型、判断范围、判断格式。可以把接口文档发给 AI,让它自动生成完整的校验代码。
准备
pip install openai==1.30.0目录结构:
validator_generator_ai/
api_spec.txt # 接口参数描述
gen_validator.py
validators.py # 生成的校验代码api_spec.txt 示例:
接口:创建用户方法:POST参数: username: 字符串,必填,3-20个字符,只能包含字母数字下划线 email: 字符串,必填,必须是合法邮箱格式 age: 整数,可选,范围0-150 phone: 字符串,可选,必须是11位手机号 role: 字符串,可选,只能是 admin/user/guest 之一gen_validator.py
import os
from pathlib import Path
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def read_spec(path: str) -> str:
return Path(path).read_text(encoding="utf-8")
def ask_ai_to_generate_validator(spec: str) -> str:
system = (
"你是一个Python后端开发专家,擅长写参数校验代码。\n"
"我会给你一个接口的参数描述,请帮我生成一个完整的参数校验函数。\n"
"要求:\n"
"1)用Python写,使用一个函数,接收一个dict参数;\n"
"2)对每个参数进行校验,不通过则抛出 ValueError 并说明原因;\n"
"3)代码要完整可运行,不要省略 import;\n"
"4)用纯文本输出,不要用markdown。"
)
user = f"接口参数描述:\n{spec}"
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user},
],
temperature=0.2,
)
return resp.choices[0].message.content.strip()
def main():
spec_path = input("请输入接口描述文件路径(默认 api_spec.txt):").strip() or "api_spec.txt"
spec = read_spec(spec_path)
print("正在生成校验代码...\n")
code = ask_ai_to_generate_validator(spec)
out = Path("validators.py")
out.write_text(code, encoding="utf-8")
print("===== 生成的校验代码 =====\n")
print(code)
print(f"\n代码已保存到:{out.resolve()}")
if __name__ == "__main__":
main()运行:
python gen_validator.py生成的 validators.py 示例:
import re
def validate_create_user(data: dict) -> None:
"""校验创建用户接口的参数"""
# username 校验
username = data.get("username")
if not username:
raise ValueError("username 不能为空")
if not isinstance(username, str):
raise ValueError("username 必须是字符串")
if not (3 <= len(username) <= 20):
raise ValueError("username 长度必须在3-20个字符之间")
if not re.match(r"^[a-zA-Z0-9_]+$", username):
raise ValueError("username 只能包含字母、数字和下划线")
# email 校验
email = data.get("email")
if not email:
raise ValueError("email 不能为空")
if not isinstance(email, str):
raise ValueError("email 必须是字符串")
if not re.match(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", email):
raise ValueError("email 格式不合法")
# age 校验(可选)
age = data.get("age")
if age is not None:
if not isinstance(age, int):
raise ValueError("age 必须是整数")
if not (0 <= age <= 150):
raise ValueError("age 必须在0-150之间")
# phone 校验(可选)
phone = data.get("phone")
if phone is not None:
if not isinstance(phone, str):
raise ValueError("phone 必须是字符串")
if not re.match(r"^1[3-9]\d{9}$", phone):
raise ValueError("phone 必须是11位合法手机号")
# role 校验(可选)
role = data.get("role")
if role is not None:
if role not in ["admin", "user", "guest"]:
raise ValueError("role 只能是 admin/user/guest 之一")
# 使用示例
if __name__ == "__main__":
# 正确数据
try:
validate_create_user({
"username": "zhangsan",
"email": "zhangsan@example.com",
"age": 25,
"phone": "13812345678",
"role": "user"
})
print("校验通过")
except ValueError as e:
print(f"校验失败:{e}")
# 错误数据
try:
validate_create_user({
"username": "ab", # 太短
"email": "not-an-email",
"age": 200, # 超出范围
})
except ValueError as e:
print(f"校验失败:{e}")