概述
利用 web 客户端调用远端服务是服务开发本实验的重要内容。其中,要点建立 API First 的开发理念,实现前后端分离,使得团队协作变得更有效率。
任务目标
- 选择合适的 API 风格,实现从接口或资源(领域)建模,到 API 设计的过程
- 使用 API 工具,编制 API 描述文件,编译生成服务器、客户端原型
- 使用 Github 建立一个组织,通过 API 文档,实现 客户端项目 与 RESTful 服务项目同步开发
- 使用 API 设计工具提供 Mock 服务,两个团队独立测试 API
- 使用 travis 测试相关模块
负责板块
服务端开发
json序列化和反序列化
REST风格
REST是使用json作为请求request和响应response的body的格式。可参考我之前的博客。
REST是由Roy Fielding提出的一种软件架构,现如今也是因为REST模式的web服务与复杂的SOAP、XML-RPC对比来说, 更加简洁,越来越多的web服务开始采用REST风格设计和实现。
实现
package controller
import (
"encoding/json"
"net/http"
"strconv"
"strings"
"github.com/Sevice-Computing/Go-REST/lib"
"github.com/Sevice-Computing/Go-REST/model"
)
// AddArticle Method
func AddArticle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
article := model.Article{}
article.Title = r.PostFormValue("title")
article.Content = r.PostFormValue("content")
article.Date = r.PostFormValue("date")
article.Tag = strings.Split(r.PostFormValue("tag"), ",")
userid, _ := strconv.Atoi(r.PostFormValue("userid"))
user := model.QueryUserbyID(int32(userid))
user.Password = ""
article.User = user
article = model.CreateArticle(article)
if article.ID == -1 {
w.WriteHeader(http.StatusInternalServerError)
} else {
buf, _ := json.Marshal(article)
w.WriteHeader(http.StatusOK)
w.Write(buf)
}
}
// DeleteArticle Method
func DeleteArticle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
id := lib.GetID(r.URL.Path)
queryArticle := model.QueryArticlebyID(id)
if queryArticle.ID != id {
w.WriteHeader(http.StatusNotFound)
} else {
err := model.DeleteArticle(id)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
} else {
w.WriteHeader(http.StatusOK)
}
}
}
// GetAllArticle Method
func GetAllArticle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
pageA := r.URL.Query()["page"]
if len(pageA) == 0 {
w.WriteHeader(http.StatusBadRequest)
return
}
page, _ := strconv.Atoi(pageA[0])
if page <= 0 {
w.WriteHeader(http.StatusBadRequest)
return
}
articles := model.QueryAllArticle()
if (len(articles)-1)/10 < page-1 {
w.WriteHeader(http.StatusNotFound)
return
} else if len(articles) > 10 && len(articles) < page*10 {
articles = articles[(page-1)*10 : page*10]
} else {
articles = articles[(page-1)*10:]
}
buf, _ := json.Marshal(articles)
w.WriteHeader(http.StatusOK)
w.Write(buf)
}
// GetArticleByID Method
func GetArticleByID(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
id := lib.GetID(r.URL.Path)
article := model.QueryArticlebyID(id)
buf, _ := json.Marshal(article)
w.WriteHeader(http.StatusOK)
w.Write(buf)
}
// GetArticleByTag Method
func GetArticleByTag(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
tagA := r.URL.Query()["tag"]
pageA := r.URL.Query()["page"]
if len(tagA) == 0 || len(pageA) == 0 {
w.WriteHeader(http.StatusBadRequest)
return
}
tag := tagA[0]
page, _ := strconv.Atoi(pageA[0])
if page <= 0 {
w.WriteHeader(http.StatusBadRequest)
return
}
articles := model.QueryAllArticle()
var result []model.Article
var flag bool
for _, article := range articles {
flag = false
for _, t := range article.Tag {
if t == tag {
flag = true
break
}
}
if flag {
result = append(result, article)
}
}
if (len(result)-1)/10 < page-1 {
w.WriteHeader(http.StatusNotFound)
return
} else if len(articles) > 10 && len(articles) < page*10 {
articles = articles[(page-1)*10 : page*10]
} else {
articles = articles[(page-1)*10:]
}
buf, _ := json.Marshal(result)
w.WriteHeader(http.StatusOK)
w.Write(buf)
}
// GetArticleByUser Method
func GetArticleByUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
userid := lib.GetID(r.URL.Path)
pageA := r.URL.Query()["page"]
if len(pageA) == 0 {
w.WriteHeader(http.StatusBadRequest)
return
}
page, _ := strconv.Atoi(pageA[0])
if page <= 0 {
w.WriteHeader(http.StatusBadRequest)
return
}
articles := model.QueryAllArticle()
var result []model.Article
for _, article := range articles {
if article.User.ID == userid {
result = append(result, article)
}
}
if (len(result)-1)/10 < page-1 {
w.WriteHeader(http.StatusNotFound)
return
} else if len(articles) > 10 && len(articles) < page*10 {
articles = articles[(page-1)*10 : page*10]
} else {
articles = articles[(page-1)*10:]
}
buf, _ := json.Marshal(result)
w.WriteHeader(http.StatusOK)
w.Write(buf)
}
// UpdateArticle Method
func UpdateArticle(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
id := lib.GetID(r.URL.Path)
queryArticle := model.QueryArticlebyID(id)
if queryArticle.ID != id {
w.WriteHeader(http.StatusNotFound)
return
}
queryArticle.Title = r.PostFormValue("title")
queryArticle.Content = r.PostFormValue("content")
queryArticle.Date = r.PostFormValue("date")
queryArticle.Tag = strings.Split(r.PostFormValue("tag"), ",")
err := model.UpdateArticle(queryArticle.ID, queryArticle)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
} else {
buf, _ := json.Marshal(queryArticle)
w.WriteHeader(http.StatusOK)
w.Write(buf)
}
}
参考博客
https://blog.csdn.net/u013210620/article/details/78450474
完整代码
详见我们小组的完整项目代码