使用 Go 构建 REST API - 适合初学者 gorilla/mux

2025-06-09

使用 Go 构建 REST API - 适合初学者

大猩猩/mux

在本文中,我们将使用 Go 构建一个简单的 REST CRUD API。

如果您想跟着一起看的话,我还制作了一个视频!

设置

让我们初始化一个简单的 Go 项目,为了简单起见,我们不会在本文中连接任何数据库。

本文的所有代码都可以在这里找到



$ go mod init github.com/karanpratapsingh/tutorials/go/crud


Enter fullscreen mode Exit fullscreen mode

让我们创造我们的main.go



$ touch main.go


Enter fullscreen mode Exit fullscreen mode

我还将安装Mux,它将有助于我们进行路由。

GitHub 徽标 大猩猩/多路复用器

gorilla/mux 包是一个强大的 HTTP 路由器和 URL 匹配器,用于构建 Go Web 服务器

大猩猩/mux

测试 代码验证 godoc 源图

大猩猩标志

该包gorilla/mux实现了一个请求路由器和调度程序,用于将传入的请求与各自的处理程序进行匹配。

mux 代表“HTTP 请求多路复用器”。与标准类似http.ServeMuxmux.Router它将传入的请求与已注册的路由列表进行匹配,并针对与 URL 或其他条件匹配的路由调用相应的处理程序。其主要功能如下:

  • 它实现了http.Handler接口,因此与标准兼容http.ServeMux
  • 可以根据 URL 主机、路径、路径前缀、方案、标头和查询值、HTTP 方法或使用自定义匹配器来匹配请求。
  • URL 主机、路径和查询值可以包含带有可选正则表达式的变量。
  • 可以构建或“反转”已注册的 URL,这有助于维护对资源的引用。
  • 路由可以用作子路由:嵌套路由仅在父路由匹配时才会进行测试。这在定义共享共同条件的路由组时非常有用,例如……

你好世界



package main

import (
    "log"
    "net/http"
  "encoding/json"

    "github.com/gorilla/mux"
)

func main() {
    router := mux.NewRouter()

    router.HandleFunc("/books", func(w http.ResponseWriter, r *http.Request) {
        json.NewEncoder(w).Encode("Hello World")
    })

    log.Println("API is running!")
    http.ListenAndServe(":4000", router)
}


Enter fullscreen mode Exit fullscreen mode

现在让我们运行我们的应用程序!



$ go run main.go


Enter fullscreen mode Exit fullscreen mode

组织

在继续之前,让我们先整理一下代码,因为我们不想把所有代码都写在里面main.go。我们将创建以下项目结构



├── cmd
│   └── main.go
├── pkg
│    ├── handlers
│    │   ├── AddBook.go
│    │   ├── DeleteBook.go
│    │   ├── GetAllBooks.go
│    │   ├── GetBook.go
│    │   └── UpdateBook.go
│    ├── mocks
│    │   └── book.go
│    └── models
│        └── book.go
├── go.sum
└── go.mod


Enter fullscreen mode Exit fullscreen mode

注意:这只是一个示例结构,如果您愿意,请随意创建我们自己的项目结构!

命令

让我们main.go转到cmd



package main

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/karanpratapsingh/tutorials/go/crud/pkg/handlers"
)

func main() {
    router := mux.NewRouter()

    // Here we'll define our api endpoints

    log.Println("API is running!")
    http.ListenAndServe(":4000", router)
}



Enter fullscreen mode Exit fullscreen mode

模型

让我们定义我们的 Book 模型pkg/models/book.go



package models

type Book struct {
    Id     int    `json:"id"`
    Title  string `json:"title"`
    Author string `json:"author"`
    Desc   string `json:"desc"`
}


Enter fullscreen mode Exit fullscreen mode

模拟

让我们创建我们的模拟pkg/mocks/book.go



package mocks

import "github.com/karanpratapsingh/tutorials/go/crud/pkg/models"

var Books = []models.Book{
    {
        Id:     1,
        Title:  "Golang",
        Author: "Gopher",
        Desc:   "A book for Go",
    },
}


Enter fullscreen mode Exit fullscreen mode

处理程序

现在,让我们开始定义我们的处理程序!

获取所有书籍

让我们将端点添加到cmd/main.go



router.HandleFunc("/books", handlers.GetAllBooks).Methods(http.MethodGet)


Enter fullscreen mode Exit fullscreen mode

创建新的处理程序pkg/handlers/GetBooks.go

在这个处理程序中,我们将简单地返回所有模拟书籍。



package handlers

import (
    "encoding/json"
    "net/http"

    "github.com/karanpratapsingh/tutorials/go/crud/pkg/mocks"
)

func GetAllBooks(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(mocks.Books)
}



Enter fullscreen mode Exit fullscreen mode

让我们启动服务器并在 Postman 中尝试一下



$ go run cmd/main.go


Enter fullscreen mode Exit fullscreen mode

这应该打印我们所有的书,目前,它应该打印我们的模拟书

获取书籍

添加新书

让我们将端点添加到cmd/main.go



router.HandleFunc("/books", handlers.AddBook).Methods(http.MethodPost)


Enter fullscreen mode Exit fullscreen mode

创建新的处理程序pkg/handlers/AddBook.go

在此处理程序中,我们将执行以下操作:

  • 读取请求主体
  • 附加到 Book mocks
  • 发送201 created回复


package handlers

import (
    "encoding/json"
    "io/ioutil"
    "log"
    "math/rand"
    "net/http"

    "github.com/karanpratapsingh/tutorials/go/crud/pkg/mocks"
    "github.com/karanpratapsingh/tutorials/go/crud/pkg/models"
)

func AddBook(w http.ResponseWriter, r *http.Request) {
    // Read to request body
    defer r.Body.Close()
    body, err := ioutil.ReadAll(r.Body)

    if err != nil {
        log.Fatalln(err)
    }

    var book models.Book
    json.Unmarshal(body, &book)

    // Append to the Book mocks
    book.Id = rand.Intn(100)
    mocks.Books = append(mocks.Books, book)

    // Send a 201 created response
    w.Header().Add("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode("Created")
}


Enter fullscreen mode Exit fullscreen mode

让我们启动服务器并在 Postman 中尝试一下



$ go run cmd/main.go


Enter fullscreen mode Exit fullscreen mode

json我们应该能够通过提供正文来添加一本新书

添加书籍

通过 ID 获取书籍

让我们将端点添加到cmd/main.go



router.HandleFunc("/books/{id}", handlers.GetBook).Methods(http.MethodGet)


Enter fullscreen mode Exit fullscreen mode

创建新的处理程序pkg/handlers/GetBook.go

在此处理程序中,我们将执行以下操作:

  • 读取动态id参数
  • 遍历所有模拟书籍
  • 如果 ID 相等,则发送书籍作为响应


package handlers

import (
    "encoding/json"
    "net/http"
    "strconv"

    "github.com/gorilla/mux"
    "github.com/karanpratapsingh/tutorials/go/crud/pkg/mocks"
)

func GetBook(w http.ResponseWriter, r *http.Request) {
    // Read dynamic id parameter
    vars := mux.Vars(r)
    id, _ := strconv.Atoi(vars["id"])

    // Iterate over all the mock books
    for _, book := range mocks.Books {
        if book.Id == id {
            // If ids are equal send book as a response
            w.Header().Add("Content-Type", "application/json")
            w.WriteHeader(http.StatusOK)

            json.NewEncoder(w).Encode(book)
            break
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

让我们启动服务器并在 Postman 中尝试一下



$ go run cmd/main.go


Enter fullscreen mode Exit fullscreen mode

获取书籍

通过 ID 更新书籍

让我们将端点添加到cmd/main.go



router.HandleFunc("/books/{id}", handlers.UpdateBook).Methods(http.MethodPut)


Enter fullscreen mode Exit fullscreen mode

创建新的处理程序pkg/handlers/UpdateBook.go

在此处理程序中,我们将执行以下操作:

  • 读取动态id参数
  • 读取请求主体
  • 遍历所有模拟书籍
  • 当书籍 ID 与动态 ID 匹配时更新并发送响应


package handlers

import (
    "encoding/json"
    "io/ioutil"
    "log"
    "net/http"
    "strconv"

    "github.com/gorilla/mux"
    "github.com/karanpratapsingh/tutorials/go/crud/pkg/mocks"
    "github.com/karanpratapsingh/tutorials/go/crud/pkg/models"
)

func UpdateBook(w http.ResponseWriter, r *http.Request) {
    // Read dynamic id parameter
    vars := mux.Vars(r)
    id, _ := strconv.Atoi(vars["id"])

    // Read request body
    defer r.Body.Close()
    body, err := ioutil.ReadAll(r.Body)

    if err != nil {
        log.Fatalln(err)
    }

    var updatedBook models.Book
    json.Unmarshal(body, &updatedBook)

    // Iterate over all the mock Books
    for index, book := range mocks.Books {
        if book.Id == id {
            // Update and send a response when book Id matches dynamic Id
            book.Title = updatedBook.Title
            book.Author = updatedBook.Author
            book.Desc = updatedBook.Desc

            mocks.Books[index] = book
            w.Header().Add("Content-Type", "application/json")
            w.WriteHeader(http.StatusOK)

            json.NewEncoder(w).Encode("Updated")
            break
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

让我们启动服务器并在 Postman 中尝试一下



$ go run cmd/main.go


Enter fullscreen mode Exit fullscreen mode

更新书

根据 ID 删除书籍

让我们将端点添加到cmd/main.go



router.HandleFunc("/books/{id}", handlers.DeleteBook).Methods(http.MethodDelete)


Enter fullscreen mode Exit fullscreen mode

创建新的处理程序pkg/handlers/DeleteBook.go

在此处理程序中,我们将执行以下操作:

  • 读取动态id参数
  • 遍历所有模拟书籍
  • 如果书籍 ID 与动态 ID 匹配,则删除书籍并发送响应


package handlers

import (
    "encoding/json"
    "net/http"
    "strconv"

    "github.com/gorilla/mux"
    "github.com/karanpratapsingh/tutorials/go/crud/pkg/mocks"
)

func DeleteBook(w http.ResponseWriter, r *http.Request) {
    // Read the dynamic id parameter
    vars := mux.Vars(r)
    id, _ := strconv.Atoi(vars["id"])

    // Iterate over all the mock Books
    for index, book := range mocks.Books {
        if book.Id == id {
            // Delete book and send a response if the book Id matches dynamic Id
            mocks.Books = append(mocks.Books[:index], mocks.Books[index+1:]...)

            w.Header().Add("Content-Type", "application/json")
            w.WriteHeader(http.StatusOK)
            json.NewEncoder(w).Encode("Deleted")
            break
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

让我们启动服务器并在 Postman 中尝试一下



$ go run cmd/main.go


Enter fullscreen mode Exit fullscreen mode

删除书

后续步骤Next steps

好了,我们用 Go 构建了一个基本的 CRUD API!下一步可能是将我们的 API 与像 PostgreSQL 这样的真正数据库连接起来,我们将在下一部分中详细探讨!

如上所述,代码可在此处获取

我希望这对您有所帮助,如果您遇到任何问题,请随时联系我们。

祝你有美好的一天!

鏂囩珷鏉ユ簮锛�https://dev.to/karanpratapsingh/build-a-rest-api-with-go-for-beginners-3gp
PREV
将 React 应用部署到 S3 和 Cloudfront
NEXT
回顾一年的远程工作