【导读】本文用详细例子介绍了 Rest API 的项目实现。
⒈ 从 0 开始
在实现动态 API 之前,先来实现一个简单的静态页面渲染
package main
import (
"fmt"
"log"
"net/http"
)
func homePage(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "HomePage")
fmt.Println("加载 HomePage 完成")
}
func handleRequests() {
http.HandleFunc("/", homePage)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func main() {
handleRequests()
}
其中,函数 homePage
负责渲染静态页面,而 handleRequests
负责将所有对 URL 根路径的请求路由到 homePage
。
⒉ 路由
在实际应用中,同一服务中会包含多个 API,针对不同的功能进行响应,所以必须用到路由模块。这里我们使用第三方包 gorilla/mux
来实现路由功能。
func handleRequests() {
myRouter := mux.NewRouter()
myRouter.HandleFunc("/", homePage)
// 列表
myRouter.HandleFunc("/all", listAdx)
// 详情
myRouter.HandleFunc("/adx/{id}", detailAdx).Methods("GET")
// 新建
myRouter.HandleFunc("/adx", createAdx).Methods("POST")
// 编辑
myRouter.HandleFunc("/adx/{id}", updateAdx).Methods("POST")
// 删除
myRouter.HandleFunc("/adx/{id}", deleteAdx). Methods("DELETE")
log.Fatal(http.ListenAndServe(":8080", myRouter))
}
解析路由中的参数
通常在一些特定功能的 API 中,都会通过路由传参(如上例中的详情 API),此时我们首先需要从 API 中解析参数。gorilla/mux
中为我们提供了解析路由方式传参的方法
vars := mux.Vars(r)
id := vars["id"]
⒊ ORM
golang 与数据库交互常用的第三方包为 go-sql-driver
,但这里我们使用另一个第三方包gorm
。gorm
的使用方法与 PHP 中的 ORM 的使用方法非常相似,既可以运行原生的 SQL 语句,还可以进行链式调用。
-
定义结构体
package main
type Adx struct {
Id int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
-
初始化数据库连接(数据库连接信息配置在 .env 文件中,这里使用 dotenv 来读取配置信息,所以需要引入 autoload
)
package main
import (
"fmt"
_ "github.com/joho/godotenv/autoload"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
"os"
)
var (
host string
port string
dbName string
username string
password string
timeout string
DB *gorm.DB
)
func init(){
host := os.Getenv("HOST")
port := os.Getenv("PORT")
dbName := os.Getenv("DATABASE")
username := os.Getenv("USERNAME")
password := os.Getenv("PASSWORD")
timeout := os.Getenv("TIMEOUT")
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?timeout=%s&charset=utf8mb4&parseTime=True&loc=Local", username, password, host, port, dbName, timeout)
fmt.Println(dsn)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err.Error())
}
DB = db
}
-
执行数据的 CURD 操作
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"io/ioutil"
"net/http"
"strconv"
)
func listAdx(w http.ResponseWriter, r *http.Request) {
var records []Adx
DB.Table("adx").
Scan(&records)
json.NewEncoder(w).Encode(records)
}
func detailAdx(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
var adx Adx
DB.Table("adx").
Where("id = ?", id).
First(&adx)
json.NewEncoder(w).Encode(adx)
}
func createAdx(w http.ResponseWriter, r *http.Request) {
var adxs []Adx
request, _ := ioutil.ReadAll(r.Body)
json.Unmarshal(request, &adxs)
fmt.Printf("%+v\n", adxs)
DB.Table("adx").
Create(&adxs)
json.NewEncoder(w).Encode(adxs)
}
func updateAdx(w http.ResponseWriter, r *http.Request) {
var adx Adx
vars := mux.Vars(r)
id, _ := strconv.Atoi(vars["id"])
fmt.Printf("id = %d\n", id)
request,_ := ioutil.ReadAll(r.Body)
json.Unmarshal(request, &adx)
fmt.Printf("%+v\n", adx)
DB.Table("adx").
Where("id = ?", id).
Updates(adx)
if DB.Error != nil {
json.NewEncoder(w).Encode(DB.Error)
} else {
adx.Id = id
json.NewEncoder(w).Encode(adx)
}
}
func deleteAdx(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, _ := strconv.Atoi(vars["id"])
// 判断记录是否存在
var count int64
DB.Table("adx").
Where("id = ?", id).
Count(&count)
if count == 0 {
json.NewEncoder(w).Encode("记录不存在")
return
}
DB.Table("adx").
Delete(&Adx{}, id)
if DB.Error != nil {
json.NewEncoder(w).Encode(DB.Error)
} else {
json.NewEncoder(w).Encode("操作成功")
}
}
上述代码中,路由传参通过 gorilla/mux
包中的方法解析,但 POST 传参则需要通过 ioutil
和 json
来解析。
⒋ API 跨域
在目前 web 应用前后端分离的背景下,要求后端 API 支持跨域。在 go 语言开发的 API 中要实现跨域,仍然需要借助第三方包,这里使用 github.com/rs/cors
。
package main
import (
"github.com/gorilla/mux"
"github.com/rs/cors"
"log"
"net/http"
)
func handleRequests() {
myRouter := mux.NewRouter()
myRouter.HandleFunc("/", homePage)
// 列表
myRouter.HandleFunc("/all", listAdx)
// 详情
myRouter.HandleFunc("/adx/{id}", detailAdx).Methods("GET")
// 新建
myRouter.HandleFunc("/adx", createAdx).Methods("POST")
// 编辑
myRouter.HandleFunc("/adx/{id}", updateAdx).Methods("POST")
// 删除
myRouter.HandleFunc("/adx/{id}", deleteAdx). Methods("DELETE")
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
})
handler := c.Handler(myRouter)
log.Fatal(http.ListenAndServe(":8080", handler))
}
在实际应用中,为了安全性考虑,AllowedOrigins
通常设置为实际使用的域名,这里只是作为 DEMO 演示,所以设置成了 *
。
转自:
juejin.cn/post/6945246548208910344
- EOF -
Go 开发大全
参与维护一个非常全面的Go开源技术资源库。日常分享 Go, 云原生、k8s、Docker和微服务方面的技术文章和行业动态。
关注后获取
回复 Go 获取6万star的Go资源库
分享、点赞和在看
支持我们分享更多好文章,谢谢!
文章评论