Go 语言 API 开发
1. 概述和要求
REST 是 Representational State Transfer 的缩写。可以使用 REST 来公开 Web 应用程序中的信息,并允许其他应用程序访问该信息。REST 本质上是一种可用于让 Web 应用程序访问资源以及另一个系统上资源状态信息的架构。通过使用 RESTful API,可以与其他服务器和系统进行交互。
下面将介绍如何创建一些有助于处理远程进程的元素。
- 请求:请求是 HTTP 请求。 API 内部的所有请求都是以 HTTP 请求的形式进行的。
- 处理程序:处理程序是一个处理客户端传入请求的函数。每种类型的请求都应该有一个适当的处理程序进行处理,并向该请求提供响应。
- 路由器:路由器是将一个 API 的端点映射到相应的处理程序的函数。
我们的目标是创建一个完整的 RESTful API,该 API 使用 GET、POST、PUT 和 DELETE 这 4 种 HTTP 请求来创建、读取、更新和删除数据(完成数据的 CRUD 操作)。CRUD 操作对应的 HTTP 请求如下:
- POST: 向数据集中添加新数据。
- GET:检索现有数据
- PUT: 更新现有数据
- DELETE: 删除现有数据
2. 第一步:创建数据集和一个简单的 API
第一步是规划基本元素并将其添加到程序中。要构建 API,需要使用以下包。
- encoding/json: 这个包可以把从请求中接收到的 JSON 数据解析为 Go 数据,反之亦然。
- log: log 包允许为 API 实现日志功能,例如记录请求中的错误。
- net/http:这个包允许接收、解析和发送 HTTP 请求。
创建一个新程序并添加所需的包,如下代码所示:
package mainimport ("encoding/json""fmt""log""net/http"
)
2.1 定义数据集
下一步是定义将对其执行 CRUD 操作的数据集。对于这个简单的例子,我们希望从以下字段开始。
- Number: 帐号编号
- Balance: 当前帐户余额
- Desc: 帐户类型
这个数据集的定义将作为一个基本表示,但如果有必要,可以包括其他字段。可以将这些字段映射到 JSON 数据集中的相应字段。
type Account struct {Number string 'json:"AccountNumber"'Balance string 'json:"Balance"'Desc string 'json:"AccountDescription"'
}
我们还将创建一个帐户数据集并将其存储在一个切片中。因为有多个不同的函数来访问此数据集,所以在 main 函数之外将它定义为全局变量。直接在结构体之后添加这个变量。
var Accounts []Account
另一种选择是将 Accounts 数据集创建为局部变量,然后将其传递给每个函数。
package mainimport ("encoding/json""fmt""log""net/http""github.com/gorilla/mux""io/ioutil"
)// we create a type Account that will be used to represent a bank account
type Account struct {Number string `json:"AccountNumber"`Balance string `json:"Balance"`Desc string `json:"AccountDescription"`
}// we use Accounts as a global variable because it is used by
// several functions in the code
var Accounts []Account// implement the homePage
// use the ResponseWriter w to display some text when we visit the home page
func homePage(w http.ResponseWriter, r *http.Request){fmt.Fprintf(w, "Welcome to our bank!")// we can use a print command to log the request or we can log it to a file, etc.fmt.Println("Endpoint: /")
}// handleRequests will process HTTP requests and redirect them to
// the appropriate Handle function
func handleRequests() {// create a router to handle our requests from the mux package.router := mux.NewRouter().StrictSlash(true)// access root pagerouter.HandleFunc("/", homePage)// returnAllAccountsrouter.HandleFunc("/accounts", returnAllAccounts)// return requested accountrouter.HandleFunc("/account/{number}", returnAccount)// create new accountrouter.HandleFunc("/account", createAccount).Methods("POST")// delete requested accountrouter.HandleFunc("/account/{number}", deleteAccount).Methods("DELETE")// define the localhostlog.Fatal(http.ListenAndServe(":10000", router))
}// return the dataset Accounts in a JSON format
func returnAllAccounts(w http.ResponseWriter, r *http.Request){// we use the Encode function to convert the Account slice into a json objectjson.NewEncoder(w).Encode(Accounts)
}// return a single account
func returnAccount(w http.ResponseWriter, r *http.Request){vars := mux.Vars(r)key := vars["number"]for _, account := range Accounts {if account.Number == key {json.NewEncoder(w).Encode(account)}}
}// create a new account
func createAccount(w http.ResponseWriter, r *http.Request) {reqBody, _ := ioutil.ReadAll(r.Body)var account Accountjson.Unmarshal(reqBody, &account)Accounts = append(Accounts, account)json.NewEncoder(w).Encode(account)
}func deleteAccount(w http.ResponseWriter, r *http.Request) {// use mux to parse the path parametersvars := mux.Vars(r)// extract the account number of the account we wish to deleteid := vars["number"]// we then need to loop through datasetfor index, account := range Accounts {// if our id path parameter matches one of our// account numbersif account.Number == id {// updates our dataset to remove the accountAccounts = append(Accounts[:index], Accounts[index + 1:]...)}}
}func main() {// initialize the datasetAccounts = []Account{Account{Number: "C45t34534", Balance: "24545.5", Desc: "Checking Account"},Account{Number: "S3r53455345", Balance: "444.4", Desc: "Savings Account"},}// execute handleRequests, which will kick off the API // we can access the API using the the URL defined abovehandleRequests()
}