Our First API in Go
Gorilla
$ go get github.com/gorilla/mux import "github.com/gorilla/mux"
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
type API struct {
Message string `json:"message"`
}
func hello(w http.ResponseWriter, r *http.Request) {
urlParams := mux.Vars(r)
name := urlParams["user"]
HelloMessage := "hello, " + name
message := API{HelloMessage}
output, err := json.Marshal(message)
if err != nil {
fmt.Println("Something went wrong")
}
fmt.Fprintf(w, string(output))
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/api/{user:[0-9]+}", hello)
http.Handle("/", r)
http.ListenAndServe(":8080", nil)
}
Routes
在路由方面的三方包有Pat, Routes, Gorilla Mux工具箱. 三者中Pat的性能最好,但路由比较复杂的性况下还是使用Routes或者 Gorilla. 建议使用Gorilla Mux
Setting data via HTTP
现在我们已经测试了如何处理路由,现在让我们通过REST终端来向数据库注入数据。
在这种情况下,我们会使用POST方法来请求,因为它可以传输大量的数据。可以避免GET请求对数据长度的限制。
从技术上讲,在create-read-update-delete(CRUD)中,PUT是用来创建数据的。但多年来都不使用PUT, 而是作为教程的注解来讲。最近,有人支持恢复PUT(and DELETE)的相应地位。Go(and Gorilla)允许你将请求归入到PUT(或者DELETE)
Connecting to MySQL
Go有大量的内置数据库连接设施和第三方数据库连接包。Go默认的SQL包是database/sql, 它允许利用一些通用的标准连接所有的数据库。
然而,我们并不需要创建自己的Mysql连接(至少现在不需要),我们可以使用第三方的库。这里有许多这样的库,但我们将使用Go-Mysql-Driver.
你可以通过 go get github.com/go-sql-driver/mysql 安装
对于本书中的例子,我们假设MySQL运行在本地的3306标准端口上。如果不是,你必须调整例子。
我们在导入包的地方,有两点增加:sql包和上面的MySQL驱动。但MySQl驱动前有下划线
package main
import
(
"database/sql"
_ "github.com/go-sql-driver/mysql"
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"net/http"
)
我们将依然使用Gorilla来增加一个端点,用来设置或者创建数据,我们将使用 PUT或者POST, 但对于这个例子,在URL中添加参数是最简单的方式。以下是设置的路径:
routes := mux.NewRouter()
routes.HandleFunc("/api/user/create", CreateUser).Methods("GET")
我们的CreateUser函数将接收多个参数——user, email, first, and last. 以下是整个User struct结构:
type User struct {
ID int "json:id"
Name string "json:username"
Email string "json:email"
First string "json:first"
Last string "json:last"
}
以下让我们看看CreateUser函数:
func CreateUser(w http.ResponseWriter, r *http.Request) {
NewUser := User{}
NewUser.Name = r.FormValue("user")
NewUser.Email = r.FormValue("email")
NewUser.First = r.FormValue("first")
NewUser.Last = r.FormValue("last")
output, err := json.Marshal(NewUser)
fmt.Println(string(output))
if err != nil {
fmt.Println("Something went wrong!")
}
sql := "INSERT INTO users set user_nickname='" + NewUser.Name + "',
user_first='" + NewUser.First + "', user_last='" + NewUser.Last + "',
user_email='" + NewUser.Email + "'"
q, err := database.Exec(sql)
if err != nil {
fmt.Println(err)
}
fmt.Println(q)
}
数据库表的结构如下
create database social_network;
CREATE TABLE users (
user_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
user_nickname VARCHAR(32) NOT NULL,
user_first VARCHAR(32) NOT NULL,
user_last VARCHAR(32) NOT NULL,
user_email VARCHAR(128) NOT NULL,
PRIMARY KEY (user_id),
UNIQUE INDEX user_nickname (user_nickname)
)
传递的地址为
http://localhost:8080/api/user/create? user=nkozyra&first=Nathan&last=Kozyra&[email protected].
以下是整个程序
package main
import (
"database/sql"
"encoding/json"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/gorilla/mux"
"log"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"username"`
Email string `json:"email"`
First string `json:"first"`
Last string `json:"last"`
}
var db *sql.DB
func CreateUser(w http.ResponseWriter, r *http.Request) {
NewUser := User{}
NewUser.Name = r.FormValue("user")
NewUser.Email = r.FormValue("email")
NewUser.First = r.FormValue("first")
NewUser.Last = r.FormValue("last")
output, err := json.Marshal(NewUser)
fmt.Println(string(output))
if err != nil {
fmt.Println("Something went wrong!")
}
stmt, err := db.Prepare("INSERT INTO users(user_nickname, user_first, user_last, user_email) values(?, ?, ?, ?)")
if err != nil {
fmt.Println(err)
}
defer stmt.Close()
result, err := stmt.Exec(NewUser.Name, NewUser.First, NewUser.Last, NewUser.Email)
if err != nil {
fmt.Println(err)
}
affect, err := result.RowsAffected()
if err != nil {
panic(err)
}
fmt.Printf("%d\n", affect)
}
func GetUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Pragma", "no-cache")
urlParams := mux.Vars(r)
id := urlParams["id"]
ReadUser := User{}
err := db.QueryRow("select * from users where user_id=?", id).Scan(&ReadUser.ID, &ReadUser.Name, &ReadUser.First, &ReadUser.Last, &ReadUser.Email)
switch {
case err == sql.ErrNoRows:
fmt.Fprintf(w, "No such user")
case err != nil:
log.Fatal(err)
default:
output, _ := json.Marshal(ReadUser)
fmt.Fprintf(w, string(output))
}
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/api/user/create", CreateUser).Methods("GET")
r.HandleFunc("/api/user/read/{id:[0-9]+}", GetUser)
http.Handle("/", r)
d, err := sql.Open("mysql", "root:root@/social_network")
if err != nil {
fmt.Println("aa")
panic(err.Error())
}
defer d.Close()
err = d.Ping()
if err != nil {
panic(err.Error())
}
db = d
http.ListenAndServe(":8080", nil)
}