feat(api): 实现三端统一的JSON API响应契约
- 新增`api_response.py`统一响应封装工具类,提供标准成功/错误响应构造方法 - 重构WonderQ-Admin全局异常处理器,将所有异常转换为标准响应格式 - 修改所有公共和管理端接口的返回逻辑,统一使用`code`(与HTTP状态码一致)、`msg`和`data`的三层结构 - 新增`api-response-contract.md`文档,定义完整的三端统一JSON响应规范 - 更新所有领域API文档,明确业务数据需位于`data`字段内,补充响应格式说明 - 为WonderQ-MiniAPP和WonderQ-Admin-UI新增响应解析逻辑和类型定义,自动完成协议校验和错误处理 - 更新所有测试用例,适配新的响应结构确保接口符合契约要求 - 新增`module-config-api.md`模块配置API文档,补充站点模块配置的接口约定 - 更新项目README文档,调整文档分类顺序将响应契约置于首位
This commit is contained in:
1 parent
d16924584c
commit
e082bd2d98
28 files changed
+993
-383
No files matched your search
@@ -3,6 +3,7 @@ from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
from .shared import site_config
|
||||
from ..auth import create_customer_token, require_customer
|
||||
from ..api_response import success_response
|
||||
from ..database import get_db
|
||||
from ..models import ConciergeAdvisor, Customer, DetailRecord, HomeExperience, HomeTeamBuilding, HomeWanfaRecommendation, HomeWildArchive, Lead, WanfaCategory
|
||||
from ..schemas import LeadCreateIn, PhoneLoginIn
|
||||
@@ -36,12 +37,12 @@ def public_customer_dict(customer: Customer) -> dict:
|
||||
|
||||
@router.get("/health")
|
||||
def health():
|
||||
return {"ok": True, "service": "miniapp-api"}
|
||||
return success_response({"ok": True, "service": "miniapp-api"})
|
||||
|
||||
|
||||
@router.get("/api/public/site-config")
|
||||
def get_site_config(db: Session = Depends(get_db)):
|
||||
return site_config(db, active_only=True)
|
||||
return success_response(site_config(db, active_only=True))
|
||||
|
||||
|
||||
@router.get("/api/public/wanfa/categories")
|
||||
@@ -51,7 +52,7 @@ def get_public_wanfa_categories(db: Session = Depends(get_db)):
|
||||
.options(selectinload(WanfaCategory.routes))
|
||||
.order_by(WanfaCategory.sortOrder.asc())
|
||||
).all()
|
||||
return {"categories": [public_wanfa_category_dict(category) for category in categories]}
|
||||
return success_response({"categories": [public_wanfa_category_dict(category) for category in categories]})
|
||||
|
||||
|
||||
@router.get("/api/public/details/{detail_key}")
|
||||
@@ -64,7 +65,7 @@ def get_public_detail(detail_key: str, db: Session = Depends(get_db)):
|
||||
)
|
||||
if not detail:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="详情不存在")
|
||||
return public_detail_dict(detail)
|
||||
return success_response(public_detail_dict(detail))
|
||||
|
||||
|
||||
@router.get("/api/public/concierge/advisors")
|
||||
@@ -74,7 +75,7 @@ def get_public_concierge_advisors(db: Session = Depends(get_db)):
|
||||
.where(ConciergeAdvisor.isActive.is_(True))
|
||||
.order_by(ConciergeAdvisor.sortOrder.asc())
|
||||
).all()
|
||||
return {"advisors": [public_concierge_advisor_dict(advisor) for advisor in advisors]}
|
||||
return success_response({"advisors": [public_concierge_advisor_dict(advisor) for advisor in advisors]})
|
||||
|
||||
|
||||
@router.get("/api/public/home")
|
||||
@@ -100,12 +101,14 @@ def get_public_home(db: Session = Depends(get_db)):
|
||||
.where(HomeWanfaRecommendation.isActive.is_(True))
|
||||
.order_by(HomeWanfaRecommendation.sortOrder.asc())
|
||||
).all()
|
||||
return {
|
||||
"experiences": [public_home_experience_dict(item) for item in experiences],
|
||||
"teamBuildings": [public_home_team_building_dict(item) for item in team_buildings],
|
||||
"wildArchives": [public_home_wild_archive_dict(item) for item in wild_archives],
|
||||
"playRecommendations": [public_home_wanfa_recommendation_dict(item) for item in play_recommendations],
|
||||
}
|
||||
return success_response(
|
||||
{
|
||||
"experiences": [public_home_experience_dict(item) for item in experiences],
|
||||
"teamBuildings": [public_home_team_building_dict(item) for item in team_buildings],
|
||||
"wildArchives": [public_home_wild_archive_dict(item) for item in wild_archives],
|
||||
"playRecommendations": [public_home_wanfa_recommendation_dict(item) for item in play_recommendations],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/public/home/team-buildings/{team_building_id}")
|
||||
@@ -118,7 +121,7 @@ def get_public_team_building(team_building_id: str, db: Session = Depends(get_db
|
||||
)
|
||||
if not team_building:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="团队共创不存在")
|
||||
return public_home_team_building_detail_dict(team_building)
|
||||
return success_response(public_home_team_building_detail_dict(team_building))
|
||||
|
||||
|
||||
@router.get("/api/public/home/wild-archives")
|
||||
@@ -128,7 +131,7 @@ def list_public_wild_archives(db: Session = Depends(get_db)):
|
||||
.where(HomeWildArchive.isActive.is_(True))
|
||||
.order_by(HomeWildArchive.sortOrder.asc())
|
||||
).all()
|
||||
return {"items": [public_home_wild_archive_dict(item) for item in archives]}
|
||||
return success_response({"items": [public_home_wild_archive_dict(item) for item in archives]})
|
||||
|
||||
|
||||
@router.get("/api/public/home/wild-archives/{archive_id}")
|
||||
@@ -141,7 +144,7 @@ def get_public_wild_archive(archive_id: str, db: Session = Depends(get_db)):
|
||||
)
|
||||
if not archive:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="客片案例不存在")
|
||||
return public_home_wild_archive_detail_dict(archive)
|
||||
return success_response(public_home_wild_archive_detail_dict(archive))
|
||||
|
||||
|
||||
@router.post("/api/public/auth/phone-login")
|
||||
@@ -160,12 +163,12 @@ def phone_login(body: PhoneLoginIn, db: Session = Depends(get_db)):
|
||||
db.flush()
|
||||
db.commit()
|
||||
db.refresh(customer)
|
||||
return {"token": create_customer_token(customer), "customer": public_customer_dict(customer)}
|
||||
return success_response({"token": create_customer_token(customer), "customer": public_customer_dict(customer)})
|
||||
|
||||
|
||||
@router.get("/api/public/auth/me")
|
||||
def current_customer(customer: Customer = Depends(require_customer)):
|
||||
return public_customer_dict(customer)
|
||||
return success_response(public_customer_dict(customer))
|
||||
|
||||
|
||||
@router.post("/api/public/leads", status_code=status.HTTP_201_CREATED)
|
||||
@@ -174,4 +177,4 @@ def create_lead(body: LeadCreateIn, db: Session = Depends(get_db)):
|
||||
db.add(lead)
|
||||
db.commit()
|
||||
db.refresh(lead)
|
||||
return {"id": lead.id, "status": lead.status}
|
||||
return success_response({"id": lead.id, "status": lead.status}, status_code=status.HTTP_201_CREATED)
|
||||
Reference in new issue
Block a user