如何使用本地模块用Golang构建REST API
Go是一种在开发者中快速增长的语言。Golang生态系统有大量的本地库。然而,它也有第三方库,开发者可以用它来构建API。
在用Go创建REST API时,你可以选择使用各种第三方库,如Gorm、Go fiber、Gin、fast HTTP等。
开发人员也可以使用Golang的本地库。这些库在构建API时不需要你把它们下载到你的本地项目中。
在本指南中,我们将使用Golang的本地库构建一个基本的REST API。我们将不使用任何第三方库,也就是说,我们不会在本地项目中下载任何库。
先决条件
要跟上本教程,读者需要。
- 一些Golang的基本知识。
- 在你的电脑上安装一个IDE(最好是VS Code)。
- 在你的电脑上安装Go。
一旦你安装了Go,运行下面的命令来验证Go的版本。
go version
开始了解如何编写和运行 Golang 程序。
设置一个Golang项目
要启动一个Go项目,首先需要在项目中初始化Go。
在你希望你的应用程序所在的地方创建一个项目文件夹。打开指向新创建目录的命令行,然后使用以下命令初始化 Golang。
go mod init native-go-api
这将通过创建一个go.mod 文件来实例化Go。你所安装的任何Go软件包及其依赖项都会保存在这里。
go.mod 文件有一个native-go-api 模块名称。这可以帮助你创建本地模块并导入它们,这样你项目的其他本地模块就可以使用它们。
使用本地模块创建一个CRUD Golang REST API
让我们深入了解并使用本地模块创建一个 Golang REST API。在本教程中,我们将创建一个简单的电影API。这将有助于展示如何在一个典型的Golang应用程序中使用这些本地库。
首先,你需要对你希望你的API与之交互的数据进行建模。要做到这一点,在你项目的根目录下创建一个models 文件夹。
然后创建一个movie.go 文件并添加以下模型。
package models
// Movie for modeling data dummy
type Movie struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
}
一个模型设定了你的API的一个蓝图。它设置了数据和它的值。这为API将使用的每个电影属性添加了数据类型。
当使用Go来创建一个模型时,使用关键字struct 。在这里,设置一个Movie 类型的struct ,并添加其属性,如上面的代码块所示。
这个API将与作为应用数据库的假数据进行交互。因此,在你的应用程序中创建一个假的数据库。
要做到这一点,在你的项目目录中创建一个文件夹db 。在这个db 文件夹中,创建一个db.go 文件并添加以下代码。
package db
import ("native-go-api/models")
// set up a database dummy
var (Moviedb = make(map[string]models.Movie))
这将建立一个假的数据库,Moviedb 。这将使用make 内置函数,它分配并初始化一个类型为map 的内存对象。
它还需要一个类型作为它的第一个参数,make 类型返回与它的参数类型相同的数据。在这里,make 将指为电影数据设置的Movie 模型的类型。
设置电影处理程序
一个API使用HTTP方法与你的数据进行交互。因此,你需要设置正确的函数来引用HTTP方法,如GET,POST,PUT, 和DELETE 。
这也将设置每个HTTP方法应该返回的请求和响应信息。
在这个例子中,API将始终以JSON格式返回任何数据。我们需要设置一个ReturnJsonResponse ,该函数将以JSON格式返回电影数据。
要做到这一点,在你的项目目录下创建一个utils 文件夹。在这个utils 文件夹中,创建一个utils.go 文件并添加以下代码。
package utils
import (
"net/http"
)
// ReturnJsonResponse function for returning movies data in JSON format
func ReturnJsonResponse(res http.ResponseWriter, httpCode int, resMessage []byte) {
res.Header().Set("Content-type", "application/json")
res.WriteHeader(httpCode)
res.Write(resMessage)
}
这将使用Go的本地http 模块。ReturnJsonResponse 函数将转换HTTP服务器返回的任何响应,并将Content-type 设置为JSON。
一旦设置完毕,就指定你的HTTP处理函数。首先,在你的项目目录中创建一个handler 文件夹。
在这个handler 文件夹中,创建一个movies.go 文件,开始导入Go的本地模块和上面步骤中创建的本地模块,如下图所示。
package handler
import (
"native-go-api/models"
"native-go-api/db"
"native-go-api/utils"
"net/http"
"encoding/json"
)
这就导入了我们所创建的本地模块。其他使用的本地模块包括用于编码任何JSON数据的encoding/json 和用于设置基于服务器的方法、请求和响应的net/http 。
接下来,让我们创建handler ,函数如下。
创建一个API测试处理程序
设置一个测试处理程序,不与设定的API数据进行交互,以测试API是否正常工作。
// root api test handler
func TestHandler(res http.ResponseWriter, req *http.Request) {
// Add the response return message
HandlerMessage := []byte(`{
"success": true,
"message": "The server is running properly"
}`)
utils.ReturnJsonResponse(res, http.StatusOK, HandlerMessage)
}
当这个处理程序被执行时,它将返回设定的信息以显示服务器已经准备好了。
获取电影处理程序
为了获取虚拟数据库中的所有电影列表,创建一个GetMovies() ,如下图所示。
// Get Movies handler
func GetMovies(res http.ResponseWriter, req *http.Request) {
if req.Method != "GET" {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Check your HTTP method: Invalid HTTP method executed",
}`)
utils.ReturnJsonResponse(res, http.StatusMethodNotAllowed, HandlerMessage)
return
}
var movies []models.Movie
for _, movie := range db.Moviedb {
movies = append(movies, movie)
}
// parse the movie data into json format
movieJSON, err := json.Marshal(&movies)
if err != nil {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Error parsing the movie data",
}`)
utils.ReturnJsonResponse(res, http.StatusInternalServerError, HandlerMessage)
return
}
utils.ReturnJsonResponse(res, http.StatusOK, movieJSON)
}
这个处理程序将访问数据库并检查是否有任何电影记录。服务器将获取这个列表并将响应返回给用户。
服务器将把电影数据解析成JSON格式,然后返回带有获取的数据的响应信息。
获取一个单一的电影处理程序
此外,你可以从电影列表数据库中获取一个单一的电影。在这种情况下,电影结构有一个ID ,每个电影都是独一无二的。
当获取单一电影时,服务器将使用ID 值作为参数来决定用户想要获取哪部电影。
// Get a single movie handler
func GetMovie(res http.ResponseWriter, req *http.Request) {
if req.Method != "GET" {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Check your HTTP method: Invalid HTTP method executed",
}`)
utils.ReturnJsonResponse(res, http.StatusMethodNotAllowed, HandlerMessage)
return
}
if _, ok := req.URL.Query()["id"]; !ok {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "This method requires the movie id",
}`)
utils.ReturnJsonResponse(res, http.StatusInternalServerError, HandlerMessage)
return
}
id := req.URL.Query()["id"][0]
movie, ok := db.Moviedb[id]
if !ok {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Requested movie not found",
}`)
utils.ReturnJsonResponse(res, http.StatusNotFound, HandlerMessage)
return
}
// parse the movie data into json format
movieJSON, err := json.Marshal(&movie)
if err != nil {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Error parsing the movie data",
}`)
utils.ReturnJsonResponse(res, http.StatusInternalServerError, HandlerMessage)
return
}
utils.ReturnJsonResponse(res, http.StatusOK, movieJSON)
}
在这里,获取单一电影的端点将有id 作为URL参数。这个端点将只执行一个GET 的请求。
如果用户使用不同的方法,设置错误信息以显示他们应该做什么。如果用户忘记添加参数id ,添加响应返回信息。检查这个函数中实现的其他处理程序信息。
添加一个电影处理程序
要添加一个电影,使用下面的AddMovie() 函数执行POST方法。
// Add a movie handler
func AddMovie(res http.ResponseWriter, req *http.Request) {
if req.Method != "POST" {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Check your HTTP method: Invalid HTTP method executed",
}`)
utils.ReturnJsonResponse(res, http.StatusMethodNotAllowed, HandlerMessage)
return
}
var movie models.Movie
payload := req.Body
defer req.Body.Close()
// parse the movie data into json format
err := json.NewDecoder(payload).Decode(&movie)
if err != nil {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Error parsing the movie data",
}`)
utils.ReturnJsonResponse(res, http.StatusInternalServerError, HandlerMessage)
return
}
db.Moviedb[movie.ID] = movie
// Add the response return message
HandlerMessage := []byte(`{
"success": true,
"message": "Movie was successfully created",
}`)
utils.ReturnJsonResponse(res, http.StatusCreated, HandlerMessage)
}
这个函数将检查用户的有效载荷与用户想要添加的新数据。该服务将把这些数据分配给req.Body 。每个添加的电影将有所有的属性设置在Movie 模型中。
因此,如果用户未能指定这个数据字段,服务器将返回一个错误信息Error parsing the movie data 。
如果操作成功,服务器将返回一个服务器消息Movie was successfully created 。
删除一个电影处理程序
要删除一条电影记录,请将这个DeleteMovie() 函数添加到你的处理程序列表中。
// Delete a movie handler
func DeleteMovie(res http.ResponseWriter, req *http.Request) {
if req.Method != "DELETE" {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Check your HTTP method: Invalid HTTP method executed",
}`)
utils.ReturnJsonResponse(res, http.StatusMethodNotAllowed, HandlerMessage)
return
}
if _, ok := req.URL.Query()["id"]; !ok {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "This method requires the movie id",
}`)
utils.ReturnJsonResponse(res, http.StatusBadRequest, HandlerMessage)
return
}
id := req.URL.Query()["id"][0]
movie, ok := db.Moviedb[id]
if !ok {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Requested movie not found",
}`)
utils.ReturnJsonResponse(res, http.StatusNotFound, HandlerMessage)
return
}
// parse the movie data into json format
movieJSON, err := json.Marshal(&movie)
if err != nil {
// Add the response return message
HandlerMessage := []byte(`{
"success": false,
"message": "Error parsing the movie data"
}`)
utils.ReturnJsonResponse(res, http.StatusBadRequest, HandlerMessage)
return
}
utils.ReturnJsonResponse(res, http.StatusOK, movieJSON)
}
DeleteMovie() 使用 ,添加到 的参数中。根据发送的请求,这将检查出服务器应该删除的现有电影。id URL
为了让服务器删除该电影,它将参数id与保存在虚拟数据中的id进行对照。如果没有找到该电影,服务器将返回一个响应信息Requested movie not found 。
初始化服务器和路由
为了执行上述处理程序,你需要。
- 设置一个在localhost上运行的服务器。
- 初始化数据库数据。
- 设置指向每个处理程序函数的路由。
要做到这一点,在项目目录内创建一个main.go 文件。然后设置服务器。
首先,导入本地模块和Go的本地模块。
package main
import (
"fmt"
"log"
"native-go-api/db"
"native-go-api/handler"
"native-go-api/models"
"net/http"
"os"
)
这里导入以下本地模块。
fmt- 用于设置 信息。Printlnlog- 用于记录基本的应用程序信息。os- 用于访问本地计算机以在本地执行服务器。net/http- 用于设置HTTP服务器和执行服务器路线。
接下来,创建一个main() ,如下图所示。
func main() {
}
在这个函数里面。
- 添加一个打印信息,显示服务器正在运行。
log.Print("The is Server Running on localhost port 3000")
- 初始化数据库并设置假的数据库数据。
// initialize the database
db.Moviedb["001"] = models.Movie{ID: "001", Title: "A Space Odyssey", Description: "Science fiction"}
db.Moviedb["002"] = models.Movie{ID: "002", Title: "Citizen Kane", Description: "Drama"}
db.Moviedb["003"] = models.Movie{ID: "003", Title: "Raiders of the Lost Ark", Description: "Action and adventure"}
db.Moviedb["004"] = models.Movie{ID: "004", Title: "66. The General", Description: "Comedy"}
- 添加指向每个处理程序的服务器路由。
// route goes here
// test route
http.HandleFunc("/", handler.TestHandler)
// get movies
http.HandleFunc("movies", handler.GetMovies)
// get a single movie
http.HandleFunc("/movie", handler.GetMovie)
// Add movie
http.HandleFunc("/movie/add", handler.AddMovie)
// delete movie
http.HandleFunc("/movie/delete", handler.DeleteMovie)
- 设置服务器端口并启动服务器。
// listen port
err := http.ListenAndServe(":3000", nil)
// print any server-based error messages
if err != nil {
fmt.Println(err)
os.Exit(1)
}
你的服务器应该已经准备好了。要测试它,请运行go run main.go ,并开始与你的API的不同路由进行交互。
总结
本教程教你如何使用本地Go模块并创建一个基本的电影API。这些原生模块帮助开发者与vanilla Golang代码进行交互。