Refactor backend APIs to RESTful route patterns.

Align group and conversation handlers/services with path-based endpoints, and unify response/service error handling for related modules.

Made-with: Cursor
This commit is contained in:
2026-03-10 20:52:50 +08:00
parent 86ef150fec
commit 21293644b8
10 changed files with 217 additions and 189 deletions

View File

@@ -500,6 +500,7 @@ func (h *GroupHandler) HandleGetUserGroups(c *gin.Context) {
// HandleGetMyMemberInfo 获取我在群组中的成员信息
// GET /api/v1/groups/get_my_info?group_id=xxx
// GET /api/v1/groups/:id/me
func (h *GroupHandler) HandleGetMyMemberInfo(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
@@ -507,7 +508,7 @@ func (h *GroupHandler) HandleGetMyMemberInfo(c *gin.Context) {
return
}
groupID := c.Query("group_id")
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
@@ -840,6 +841,7 @@ func (h *GroupHandler) HandleCreateAnnouncement(c *gin.Context) {
// HandleGetAnnouncements 获取群公告列表
// GET /api/v1/groups/get_announcements?group_id=xxx
// GET /api/v1/groups/:id/announcements
func (h *GroupHandler) HandleGetAnnouncements(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
@@ -847,7 +849,7 @@ func (h *GroupHandler) HandleGetAnnouncements(c *gin.Context) {
return
}
groupID := c.Query("group_id")
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
@@ -1724,6 +1726,7 @@ func (h *GroupHandler) HandleRespondInvite(c *gin.Context) {
// HandleGetGroupInfo 获取群信息
// GET /api/v1/groups/get?group_id=xxx
// GET /api/v1/groups/:id
func (h *GroupHandler) HandleGetGroupInfo(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
@@ -1731,7 +1734,7 @@ func (h *GroupHandler) HandleGetGroupInfo(c *gin.Context) {
return
}
groupID := c.Query("group_id")
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
@@ -1759,6 +1762,7 @@ func (h *GroupHandler) HandleGetGroupInfo(c *gin.Context) {
// HandleGetGroupMemberList 获取群成员列表
// GET /api/v1/groups/get_members?group_id=xxx
// GET /api/v1/groups/:id/members
func (h *GroupHandler) HandleGetGroupMemberList(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
@@ -1766,7 +1770,7 @@ func (h *GroupHandler) HandleGetGroupMemberList(c *gin.Context) {
return
}
groupID := c.Query("group_id")
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "group_id is required")
return

View File

@@ -11,8 +11,8 @@ import (
"carrot_bbs/internal/dto"
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/sse"
"carrot_bbs/internal/pkg/response"
"carrot_bbs/internal/pkg/sse"
"carrot_bbs/internal/service"
)
@@ -548,7 +548,7 @@ func (h *MessageHandler) HandleDeleteConversationForSelf(c *gin.Context) {
return
}
conversationID := c.Param("id")
conversationID := getIDParam(c, "id")
if conversationID == "" {
response.BadRequest(c, "conversation id is required")
return
@@ -730,6 +730,11 @@ func (h *MessageHandler) getMyConversationParticipant(conversationID string, use
return nil, nil
}
// getIDParam 从路径参数获取 ID
func getIDParam(c *gin.Context, paramName string) string {
return c.Param(paramName)
}
// ==================== RESTful Action 端点 ====================
// HandleCreateConversation 创建会话
@@ -776,6 +781,7 @@ func (h *MessageHandler) HandleCreateConversation(c *gin.Context) {
// HandleGetConversation 获取会话详情
// GET /api/v1/conversations/get?conversation_id=xxx
// GET /api/v1/conversations/:id
func (h *MessageHandler) HandleGetConversation(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
@@ -783,7 +789,7 @@ func (h *MessageHandler) HandleGetConversation(c *gin.Context) {
return
}
conversationID := c.Query("conversation_id")
conversationID := getIDParam(c, "id")
if conversationID == "" {
response.BadRequest(c, "conversation_id is required")
return
@@ -820,6 +826,7 @@ func (h *MessageHandler) HandleGetConversation(c *gin.Context) {
// HandleGetMessages 获取会话消息
// GET /api/v1/conversations/get_messages?conversation_id=xxx
// GET /api/v1/conversations/:id/messages
func (h *MessageHandler) HandleGetMessages(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
@@ -827,7 +834,7 @@ func (h *MessageHandler) HandleGetMessages(c *gin.Context) {
return
}
conversationID := c.Query("conversation_id")
conversationID := getIDParam(c, "id")
if conversationID == "" {
response.BadRequest(c, "conversation_id is required")
return

View File

@@ -80,11 +80,8 @@ func (h *PostHandler) GetByID(c *gin.Context) {
// 注意:不再自动增加浏览量,浏览量通过 RecordView 端点单独记录
var isLiked, isFavorited bool
if currentUserID != "" {
isLiked = h.postService.IsLiked(c.Request.Context(), id, currentUserID)
isFavorited = h.postService.IsFavorited(c.Request.Context(), id, currentUserID)
}
// 获取交互状态
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, currentUserID)
// 如果有当前用户,检查与帖子作者的相互关注状态
var authorWithFollowStatus *dto.UserResponse
@@ -196,19 +193,15 @@ func (h *PostHandler) List(c *gin.Context) {
return
}
isLikedMap := make(map[string]bool)
isFavoritedMap := make(map[string]bool)
if currentUserID != "" {
for _, post := range posts {
isLiked := h.postService.IsLiked(c.Request.Context(), post.ID, currentUserID)
isFavorited := h.postService.IsFavorited(c.Request.Context(), post.ID, currentUserID)
isLikedMap[post.ID] = isLiked
isFavoritedMap[post.ID] = isFavorited
}
// 批量获取交互状态
postIDs := make([]string, len(posts))
for i, post := range posts {
postIDs[i] = post.ID
}
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
// 转换为响应结构
postResponses := dto.ConvertPostsToResponse(posts, isLikedMap, isFavoritedMap)
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
response.Paginated(c, postResponses, total, page, pageSize)
}
@@ -265,14 +258,11 @@ func (h *PostHandler) Update(c *gin.Context) {
return
}
// 获取交互状态
currentUserID := c.GetString("user_id")
var isLiked, isFavorited bool
if currentUserID != "" {
isLiked = h.postService.IsLiked(c.Request.Context(), post.ID, currentUserID)
isFavorited = h.postService.IsFavorited(c.Request.Context(), post.ID, currentUserID)
}
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), post.ID, currentUserID)
response.Success(c, dto.ConvertPostToResponse(post, isLiked, isFavorited))
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
}
// Delete 删除帖子
@@ -328,10 +318,10 @@ func (h *PostHandler) Like(c *gin.Context) {
return
}
isLiked := h.postService.IsLiked(c.Request.Context(), id, userID)
isFavorited := h.postService.IsFavorited(c.Request.Context(), id, userID)
// 获取交互状态
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
response.Success(c, dto.ConvertPostToResponse(post, isLiked, isFavorited))
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
}
// Unlike 取消点赞
@@ -357,10 +347,10 @@ func (h *PostHandler) Unlike(c *gin.Context) {
return
}
isLiked := h.postService.IsLiked(c.Request.Context(), id, userID)
isFavorited := h.postService.IsFavorited(c.Request.Context(), id, userID)
// 获取交互状态
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
response.Success(c, dto.ConvertPostToResponse(post, isLiked, isFavorited))
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
}
// Favorite 收藏帖子
@@ -386,10 +376,10 @@ func (h *PostHandler) Favorite(c *gin.Context) {
return
}
isLiked := h.postService.IsLiked(c.Request.Context(), id, userID)
isFavorited := h.postService.IsFavorited(c.Request.Context(), id, userID)
// 获取交互状态
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
response.Success(c, dto.ConvertPostToResponse(post, isLiked, isFavorited))
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
}
// Unfavorite 取消收藏
@@ -415,10 +405,10 @@ func (h *PostHandler) Unfavorite(c *gin.Context) {
return
}
isLiked := h.postService.IsLiked(c.Request.Context(), id, userID)
isFavorited := h.postService.IsFavorited(c.Request.Context(), id, userID)
// 获取交互状态
isLiked, isFavorited := h.postService.GetPostInteractionStatusSingle(c.Request.Context(), id, userID)
response.Success(c, dto.ConvertPostToResponse(post, isLiked, isFavorited))
response.Success(c, dto.BuildPostResponse(post, isLiked, isFavorited))
}
// GetUserPosts 获取用户帖子列表
@@ -435,18 +425,15 @@ func (h *PostHandler) GetUserPosts(c *gin.Context) {
return
}
// 获取当前用户ID用于判断点赞和收藏状态
isLikedMap := make(map[string]bool)
isFavoritedMap := make(map[string]bool)
if currentUserID != "" {
for _, post := range posts {
isLikedMap[post.ID] = h.postService.IsLiked(c.Request.Context(), post.ID, currentUserID)
isFavoritedMap[post.ID] = h.postService.IsFavorited(c.Request.Context(), post.ID, currentUserID)
}
// 批量获取交互状态
postIDs := make([]string, len(posts))
for i, post := range posts {
postIDs[i] = post.ID
}
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
// 转换为响应结构
postResponses := dto.ConvertPostsToResponse(posts, isLikedMap, isFavoritedMap)
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
response.Paginated(c, postResponses, total, page, pageSize)
}
@@ -463,19 +450,16 @@ func (h *PostHandler) GetFavorites(c *gin.Context) {
return
}
// 获取当前用户ID用于判断点赞和收藏状态
// 批量获取交互状态
currentUserID := c.GetString("user_id")
isLikedMap := make(map[string]bool)
isFavoritedMap := make(map[string]bool)
if currentUserID != "" {
for _, post := range posts {
isLikedMap[post.ID] = h.postService.IsLiked(c.Request.Context(), post.ID, currentUserID)
isFavoritedMap[post.ID] = h.postService.IsFavorited(c.Request.Context(), post.ID, currentUserID)
}
postIDs := make([]string, len(posts))
for i, post := range posts {
postIDs[i] = post.ID
}
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
// 转换为响应结构
postResponses := dto.ConvertPostsToResponse(posts, isLikedMap, isFavoritedMap)
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
response.Paginated(c, postResponses, total, page, pageSize)
}
@@ -492,19 +476,16 @@ func (h *PostHandler) Search(c *gin.Context) {
return
}
// 获取当前用户ID用于判断点赞和收藏状态
// 批量获取交互状态
currentUserID := c.GetString("user_id")
isLikedMap := make(map[string]bool)
isFavoritedMap := make(map[string]bool)
if currentUserID != "" {
for _, post := range posts {
isLikedMap[post.ID] = h.postService.IsLiked(c.Request.Context(), post.ID, currentUserID)
isFavoritedMap[post.ID] = h.postService.IsFavorited(c.Request.Context(), post.ID, currentUserID)
}
postIDs := make([]string, len(posts))
for i, post := range posts {
postIDs[i] = post.ID
}
isLikedMap, isFavoritedMap, _ := h.postService.GetPostInteractionStatus(c.Request.Context(), postIDs, currentUserID)
// 转换为响应结构
postResponses := dto.ConvertPostsToResponse(posts, isLikedMap, isFavoritedMap)
postResponses := dto.BuildPostsWithInteractionResponse(posts, isLikedMap, isFavoritedMap)
response.Paginated(c, postResponses, total, page, pageSize)
}

View File

@@ -42,11 +42,7 @@ func (h *UserHandler) Register(c *gin.Context) {
user, err := h.userService.Register(c.Request.Context(), req.Username, req.Email, req.Password, req.Nickname, req.Phone, req.VerificationCode)
if err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to register")
response.HandleError(c, err, "failed to register")
return
}
@@ -86,11 +82,7 @@ func (h *UserHandler) Login(c *gin.Context) {
user, err := h.userService.Login(c.Request.Context(), account, req.Password)
if err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to login")
response.HandleError(c, err, "failed to login")
return
}
@@ -118,11 +110,7 @@ func (h *UserHandler) SendRegisterCode(c *gin.Context) {
}
if err := h.userService.SendRegisterCode(c.Request.Context(), req.Email); err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to send register verification code")
response.HandleError(c, err, "failed to send register verification code")
return
}
@@ -142,11 +130,7 @@ func (h *UserHandler) SendPasswordResetCode(c *gin.Context) {
}
if err := h.userService.SendPasswordResetCode(c.Request.Context(), req.Email); err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to send reset verification code")
response.HandleError(c, err, "failed to send reset verification code")
return
}
@@ -168,11 +152,7 @@ func (h *UserHandler) ResetPassword(c *gin.Context) {
}
if err := h.userService.ResetPasswordByEmail(c.Request.Context(), req.Email, req.VerificationCode, req.NewPassword); err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to reset password")
response.HandleError(c, err, "failed to reset password")
return
}
@@ -317,11 +297,7 @@ func (h *UserHandler) SendEmailVerifyCode(c *gin.Context) {
}
if err := h.userService.SendCurrentUserEmailVerifyCode(c.Request.Context(), userID, req.Email); err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to send email verify code")
response.HandleError(c, err, "failed to send email verify code")
return
}
@@ -347,11 +323,7 @@ func (h *UserHandler) VerifyEmail(c *gin.Context) {
}
if err := h.userService.VerifyCurrentUserEmail(c.Request.Context(), userID, req.Email, req.VerificationCode); err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to verify email")
response.HandleError(c, err, "failed to verify email")
return
}
@@ -437,11 +409,7 @@ func (h *UserHandler) BlockUser(c *gin.Context) {
err := h.userService.BlockUser(c.Request.Context(), currentUserID, targetUserID)
if err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to block user")
response.HandleError(c, err, "failed to block user")
return
}
@@ -460,11 +428,7 @@ func (h *UserHandler) UnblockUser(c *gin.Context) {
err := h.userService.UnblockUser(c.Request.Context(), currentUserID, targetUserID)
if err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to unblock user")
response.HandleError(c, err, "failed to unblock user")
return
}
@@ -638,11 +602,7 @@ func (h *UserHandler) ChangePassword(c *gin.Context) {
err := h.userService.ChangePassword(c.Request.Context(), currentUserID, req.OldPassword, req.NewPassword, req.VerificationCode)
if err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to change password")
response.HandleError(c, err, "failed to change password")
return
}
@@ -659,11 +619,7 @@ func (h *UserHandler) SendChangePasswordCode(c *gin.Context) {
err := h.userService.SendChangePasswordCode(c.Request.Context(), currentUserID)
if err != nil {
if se, ok := err.(*service.ServiceError); ok {
response.Error(c, se.Code, se.Message)
return
}
response.InternalServerError(c, "failed to send change password code")
response.HandleError(c, err, "failed to send change password code")
return
}