悠家娱乐 | Linux 中国,构建一个即时消息应用(四):消息


悠家娱乐 | Linux 中国,构建一个即时消息应用(四):消息
文章图片
在这篇文章中 , 我们将对端点进行编码 , 以创建一条消息并列出它们 , 同时还将编写一个端点以更新参与者上次阅读消息的时间 。
?来源:linux.cn?作者:NicolásParada?译者:XianLeiGao?
(本文字数:7533 , 阅读时长大约:8分钟)
本文是该系列的第四篇 。
第一篇:模式
第二篇:OAuth
第三篇:对话
在这篇文章中 , 我们将对端点进行编码 , 以创建一条消息并列出它们 , 同时还将编写一个端点以更新参与者上次阅读消息的时间 。 首先在main()函数中添加这些路由 。
router.HandleFunc(''POST'',''/api/conversations/:conversationID/messages'',requireJSON(guard(createMessage)))router.HandleFunc(''GET'',''/api/conversations/:conversationID/messages'',guard(getMessages))router.HandleFunc(''POST'',''/api/conversations/:conversationID/read_messages'',guard(readMessages))
消息会进入对话 , 因此端点包含对话ID 。
创建消息
该端点处理对/api/conversations/{conversationID}/messages的POST请求 , 其JSON主体仅包含消息内容 , 并返回新创建的消息 。 它有两个副作用:更新对话last_message_id以及更新参与者messages_read_at 。
funccreateMessage(whttp.ResponseWriter,r*http.Request){varinputstruct{Contentstring`json:''content''`}deferr.Body.Close()iferr:=json.NewDecoder(r.Body).Decode(&input);err!=nil{http.Error(w,err.Error(),http.StatusBadRequest)return}errs:=make(map[string]string)input.Content=removeSpaces(input.Content)ifinput.Content==''''{errs[''content'']=''Messagecontentrequired''}elseiflen([]rune(input.Content))>480{errs[''content'']=''Messagetoolong.480max''}iflen(errs)!=0{respond(w,Errors{errs},http.StatusUnprocessableEntity)return}ctx:=r.Context()authUserID:=ctx.Value(keyAuthUserID).(string)conversationID:=way.Param(ctx,''conversationID'')tx,err:=db.BeginTx(ctx,nil)iferr!=nil{respondError(w,fmt.Errorf(''couldnotbegintx:%v'',err))return}defertx.Rollback()isParticipant,err:=queryParticipantExistance(ctx,tx,authUserID,conversationID)iferr!=nil{respondError(w,fmt.Errorf(''couldnotqueryparticipantexistance:%v'',err))return}if!isParticipant{http.Error(w,''Conversationnotfound'',http.StatusNotFound)return}varmessageMessageiferr:=tx.QueryRowContext(ctx,`INSERTINTOmessages(content,user_id,conversation_id)VALUES($1,$2,$3)RETURNINGid,created_at`,input.Content,authUserID,conversationID).Scan(&message.ID,&message.CreatedAt,);err!=nil{respondError(w,fmt.Errorf(''couldnotinsertmessage:%v'',err))return}if_,err:=tx.ExecContext(ctx,`UPDATEconversationsSETlast_message_id=$1WHEREid=$2`,message.ID,conversationID);err!=nil{respondError(w,fmt.Errorf(''couldnotupdateconversationlastmessageID:%v'',err))return}iferr=tx.Commit();err!=nil{respondError(w,fmt.Errorf(''couldnotcommittxtocreateamessage:%v'',err))return}gofunc(){iferr=updateMessagesReadAt(nil,authUserID,conversationID);err!=nil{log.Printf(''couldnotupdatemessagesreadat:%vn'',err)}}()message.Content=input.Contentmessage.UserID=authUserIDmessage.ConversationID=conversationID//TODO:notifyaboutnewmessage.message.Mine=truerespond(w,message,http.StatusCreated)}
首先 , 它将请求正文解码为包含消息内容的结构 。 然后 , 它验证内容不为空并且少于480个字符 。