Golang for Web(第一部分):使用 Golang 和 Fiber 构建您的第一个 REST API
这是Golang for Web系列的第一部分。我的目标是向新手展示如何通过将大型应用程序拆分成多个小应用程序,轻松地使用 Go 构建 REST API。在这里,我们将使用 Gofiber 构建一个简单的 TODO 应用 Web 服务器,并分离所有路由、控制器等。
Go:一种开源编程语言
Go 是一种开源编程语言,可以轻松构建简单、可靠、高效的软件。
Go 是由 Google 的 Robert Griesemer、Rob Pike 和 Ken Thompson 设计的一门静态类型编译型编程语言。Go 的语法与 C 语言类似,但具备内存安全、垃圾回收、结构化类型和 CSP 风格的并发性。(来源:维基百科)
Golang Web 版 🌐
作为一名 MERN 堆栈开发人员,我发现Fiber Web 框架与 express 非常相似,正如他们所声称的那样,对于 JS 开发人员来说,使用 Golang 构建一个漂亮而令人惊叹的 REST API 非常容易。
Fiber是一个基于 Express 的Web 框架,它基于Go 中最快的HTTP 引擎Fasthttp 构建。其设计初衷是简化快速开发,零内存分配,并注重性能。
在这里查看其惊人的基准性能 - https://docs.gofiber.io/extra/benchmarks
我们要建造什么?🤔
好了,废话不多说🤚现在是时候用 Fiber 来演示一下了。今天我们将用 Fiber 构建一个基本的 TODO 应用。我相信,看完之后,你就能轻松地用 Golang 构建 REST API 了👨🏻💻
先决条件📝
如果你有这些,那就开始吧🚀
让我们开始吧🏁
1. 设置我们的项目
首先,让我们创建一个名为的新目录fiber-todo
,并在 VS Code(或任何其他代码编辑器/ IDE)中打开此目录
现在在根目录打开终端并运行命令:
go mod init github.com/<Your_Username>/<Repo_Name>
例子 :
go mod init github.com/devsmranjan/golang-fiber-basic-todo-app
让我们通过运行以下命令在我们的项目中安装光纤:
go get -u github.com/gofiber/fiber/v2
现在在我们的根目录中创建一个名为的文件main.go
并创建两个目录routes
& controllers
。
2.创建我们的第一个服务器
现在在里面main.go
写入以下代码:
package main
import (
"github.com/gofiber/fiber/v2"
)
func main() {}
好的,你会在这里遇到一些错误,但请继续关注我🤝
现在main()
让我们在方法内部启动光纤。
app := fiber.New()
通过以下方式添加我们的第一条路线:
app.Get("/", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"message": "You are at the endpoint 😉",
})
})
最后,监听 8000 端口的服务器并捕获任何错误。
err := app.Listen(":8000")
if err != nil {
panic(err)
}
这是我们的最终代码:
package main
import (
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
// give response when at /
app.Get("/", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"message": "You are at the endpoint 😉",
})
})
// Listen on server 8000 and catch error if any
err := app.Listen(":8000")
// handle error
if err != nil {
panic(err)
}
}
现在运行我们的服务器,打开终端并在我们的根目录中运行:
go run main.go
它将显示类似这样的内容
┌───────────────────────────────────────────────────┐
│ Fiber v2.2.0 │
│ http://127.0.0.1:8000 │
│ │
│ Handlers ............. 2 Threads ............. 4 │
│ Prefork ....... Disabled PID ............. 60983 │
└───────────────────────────────────────────────────┘
现在打开浏览器,然后转到localhost:8000
。您将获得如下输出
{
"message": "You are at the endpoint 😉",
"success": true
}
哈哈哈!!!我们成功了🤟
此外,如果您想添加记录器中间件,请运行
go get -u github.com/gofiber/fiber/v2/middleware/logger
在我们的项目中导入记录器
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger" // new
)
最后,将这个中间件与我们的app
app.Use(logger.New())
这是我们的最终代码:
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger" // new
)
func main() {
app := fiber.New()
app.Use(logger.New()) // new
// give response when at /
app.Get("/", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"message": "You are at the endpoint 😉",
})
})
// Listen on server 8000 and catch error if any
err := app.Listen(":8000")
// handle error
if err != nil {
panic(err)
}
}
现在再次运行我们的服务器,localhost:8000
您可以看到终端显示了我们的请求日志,如下所示:
21:44:48 | 200 | 0s | 127.0.0.1 | GET | /
3. 确定 TODO 应用的端点
localhost:8000/api/todos
request: GET
description: To get all todos
localhost:8000/api/todos/:id
request: GET
description: Get todo by id
localhost:8000/api/todos
request: POST
input: {
title : String
}
description: Create new todo
localhost:8000/api/todos/:id
request: PUT
input: {
title : String,
completed : Boolean
}
description: Update todo
localhost:8000/api/todos/:id
request: DELETE
description: Delete todo
4. 构建我们的第一个 API 端点
步骤1:
让我们为待办事项应用程序编写第一个控制器。
打开controllers
目录并创建名为todo.go
现在controllers/todo.go
让我们进行所需的导入。
package controllers
import (
"github.com/gofiber/fiber/v2"
)
添加Todo
结构
type Todo struct {
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
让我们添加一些预定义的待办事项
var todos = []*Todo{
{
Id: 1,
Title: "Walk the dog 🦮",
Completed: false,
},
{
Id: 2,
Title: "Walk the cat 🐈",
Completed: false,
},
}
现在我们终于可以创建控制器来获取所有待办事项了
func GetTodos(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todos": todos,
},
})
}
这是我们的最终代码controllers/todo.go
:
package controllers
import (
"github.com/gofiber/fiber/v2"
)
type Todo struct {
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todos = []*Todo{
{
Id: 1,
Title: "Walk the dog 🦮",
Completed: false,
},
{
Id: 2,
Title: "Walk the cat 🐈",
Completed: false,
},
}
// get all todos
func GetTodos(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todos": todos,
},
})
}
第2步:
现在让我们为待办事项应用程序编写第一条路线并连接我们的控制器。
打开routes
目录并创建一个名为todo.go
现在routes/todo.go
让我们进行所需的导入
package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/devsmranjan/golang-fiber-basic-todo-app/controllers" // replace
)
替换github.com/devsmranjan/golang-fiber-basic-todo-app/controllers
为你的 github repo url,例如github.com/<Your_Username>/<Repo_Name>/controllers
创建第一条获取所有待办事项的路线
func TodoRoute(route fiber.Router) {
route.Get("", controllers.GetTodos)
}
这是我们的最终代码routes/todo.go
:
package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/devsmranjan/golang-fiber-basic-todo-app/controllers" // replace
)
func TodoRoute(route fiber.Router) {
route.Get("", controllers.GetTodos)
}
步骤3:
好的,这是最后一步。
返回main.go
并导入routes
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/devsmranjan/golang-fiber-basic-todo-app/routes" // new // replace
)
替换github.com/devsmranjan/golang-fiber-basic-todo-app/routes
为你的 github repo url 即github.com/<Your_Username>/<Repo_Name>/routes
现在让我们创建一个单独的函数来处理所有的路线。
func setupRoutes(app *fiber.App) {}
将所有路线从main()
一个方法移动到setupRoutes()
另一个方法。
func setupRoutes(app *fiber.App) {
// moved from main method
app.Get("/", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"message": "You are at the endpoint 😉",
})
})
}
现在setupRoutes()
从方法中调用方法main()
。
setupRoutes(app)
这是我们的最终main()
样子。
func main() {
app := fiber.New()
app.Use(logger.New())
// setup routes
setupRoutes(app) // new
// Listen on server 8000 and catch error if any
err := app.Listen(":8000")
// handle error
if err != nil {
panic(err)
}
}
现在让我们在方法api
中创建一个名为的路由组setupRoutes()
api := app.Group("/api")
/api
添加路线响应
api.Get("", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"message": "You are at the api endpoint 😉",
})
})
现在,最后,将所有待办事项路由连接到我们的api
路由组
routes.TodoRoute(api.Group("/todos"))
最终setupRoutes()
方法如下:
func setupRoutes(app *fiber.App) {
// give response when at /
app.Get("/", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"message": "You are at the endpoint 😉",
})
})
// api group
api := app.Group("/api")
// give response when at /api
api.Get("", func(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"message": "You are at the api endpoint 😉",
})
})
// connect todo routes
routes.TodoRoute(api.Group("/todos"))
}
现在运行服务器并转到http://localhost:8000/api/todos
。输出如下所示。
{
"data": {
"todos": [
{
"id": 1,
"title": "Walk the dog 🦮",
"completed": false
},
{
"id": 2,
"title": "Walk the cat 🐈",
"completed": false
}
]
},
"success": true
}
5. 让我们创建其他控制器🎛
我想你已经明白这一切是怎么运作的了。对吧?😎
现在让我们创建其他控制器。
但在此之前,让我们添加一些必需的导入controllers/todo.go
:
import (
"fmt" // new
"strconv" // new
"github.com/gofiber/fiber/v2"
)
好的。让我们创建一个控制器来创建待办事项
func CreateTodo(c *fiber.Ctx) error {
type Request struct {
Title string `json:"title"`
}
var body Request
err := c.BodyParser(&body)
// if error
if err != nil {
fmt.Println(err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse JSON",
})
}
// create a todo variable
todo := &Todo{
Id: len(todos) + 1,
Title: body.Title,
Completed: false,
}
// append in todos
todos = append(todos, todo)
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todo": todo,
},
})
}
通过 id 获取单个待办事项的控制器
func GetTodo(c *fiber.Ctx) error {
// get parameter value
paramId := c.Params("id")
// convert parameter value string to int
id, err := strconv.Atoi(paramId)
// if error in parsing string to int
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse Id",
})
}
// find todo and return
for _, todo := range todos {
if todo.Id == id {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todo": todo,
},
})
}
}
// if todo not available
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"success": false,
"message": "Todo not found",
})
}
用于更新待办事项的控制器
func UpdateTodo(c *fiber.Ctx) error {
// find parameter
paramId := c.Params("id")
// convert parameter string to int
id, err := strconv.Atoi(paramId)
// if parameter cannot parse
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse id",
})
}
// request structure
type Request struct {
Title *string `json:"title"`
Completed *bool `json:"completed"`
}
var body Request
err = c.BodyParser(&body)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse JSON",
})
}
var todo *Todo
for _, t := range todos {
if t.Id == id {
todo = t
break
}
}
if todo.Id == 0 {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"success": false,
"message": "Not found",
})
}
if body.Title != nil {
todo.Title = *body.Title
}
if body.Completed != nil {
todo.Completed = *body.Completed
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todo": todo,
},
})
}
删除待办事项的控制器
func DeleteTodo(c *fiber.Ctx) error {
// get param
paramId := c.Params("id")
// convert param string to int
id, err := strconv.Atoi(paramId)
// if parameter cannot parse
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse id",
})
}
// find and delete todo
for i, todo := range todos {
if todo.Id == id {
todos = append(todos[:i], todos[i+1:]...)
return c.Status(fiber.StatusNoContent).JSON(fiber.Map{
"success": true,
"message": "Deleted Succesfully",
})
}
}
// if todo not found
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"success": false,
"message": "Todo not found",
})
}
这是我们的最终代码controllers/todo.go
:
package controllers
import (
"fmt"
"strconv"
"github.com/gofiber/fiber/v2"
)
type Todo struct {
Id int `json:"id"`
Title string `json:"title"`
Completed bool `json:"completed"`
}
var todos = []*Todo{
{
Id: 1,
Title: "Walk the dog 🦮",
Completed: false,
},
{
Id: 2,
Title: "Walk the cat 🐈",
Completed: false,
},
}
// get all todos
func GetTodos(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todos": todos,
},
})
}
// Create a todo
func CreateTodo(c *fiber.Ctx) error {
type Request struct {
Title string `json:"title"`
}
var body Request
err := c.BodyParser(&body)
// if error
if err != nil {
fmt.Println(err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse JSON",
})
}
// create a todo variable
todo := &Todo{
Id: len(todos) + 1,
Title: body.Title,
Completed: false,
}
// append in todos
todos = append(todos, todo)
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todo": todo,
},
})
}
// get a single todo
// PARAM: id
func GetTodo(c *fiber.Ctx) error {
// get parameter value
paramId := c.Params("id")
// convert parameter value string to int
id, err := strconv.Atoi(paramId)
// if error in parsing string to int
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse Id",
})
}
// find todo and return
for _, todo := range todos {
if todo.Id == id {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todo": todo,
},
})
}
}
// if todo not available
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"success": false,
"message": "Todo not found",
})
}
// Update a todo
// PARAM: id
func UpdateTodo(c *fiber.Ctx) error {
// find parameter
paramId := c.Params("id")
// convert parameter string to int
id, err := strconv.Atoi(paramId)
// if parameter cannot parse
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse id",
})
}
// request structure
type Request struct {
Title *string `json:"title"`
Completed *bool `json:"completed"`
}
var body Request
err = c.BodyParser(&body)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse JSON",
})
}
var todo *Todo
for _, t := range todos {
if t.Id == id {
todo = t
break
}
}
if todo.Id == 0 {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"success": false,
"message": "Not found",
})
}
if body.Title != nil {
todo.Title = *body.Title
}
if body.Completed != nil {
todo.Completed = *body.Completed
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"success": true,
"data": fiber.Map{
"todo": todo,
},
})
}
// Delete a todo
// PARAM: id
func DeleteTodo(c *fiber.Ctx) error {
// get param
paramId := c.Params("id")
// convert param string to int
id, err := strconv.Atoi(paramId)
// if parameter cannot parse
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"success": false,
"message": "Cannot parse id",
})
}
// find and delete todo
for i, todo := range todos {
if todo.Id == id {
todos = append(todos[:i], todos[i+1:]...)
return c.Status(fiber.StatusNoContent).JSON(fiber.Map{
"success": true,
"message": "Deleted Succesfully",
})
}
}
// if todo not found
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"success": false,
"message": "Todo not found",
})
}
6.创建其他路线🚏
让我们为待办事项应用程序创建其他路线。
现在,在里面TodoRoute()
添加以下所有路线
route.Post("", controllers.CreateTodo)
route.Put("/:id", controllers.UpdateTodo)
route.Delete("/:id", controllers.DeleteTodo)
route.Get("/:id", controllers.GetTodo)
最后,我们的最终代码如下所示:
package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/devsmranjan/golang-fiber-basic-todo-app/controllers" // replace
)
func TodoRoute(route fiber.Router) {
route.Get("", controllers.GetTodos)
route.Post("", controllers.CreateTodo) // new
route.Put("/:id", controllers.UpdateTodo) // new
route.Delete("/:id", controllers.DeleteTodo) // new
route.Get("/:id", controllers.GetTodo) // new
}
现在我们已经准备好运行我们的服务器了😎
让我们在 Postman 中测试我们的 API。
7. 测试我们的端点
要获取所有待办事项,请GET
向localhost:8000/api/todos
要通过 ID 获取待办事项,请GET
向localhost:8000/api/todos/:id
此处发出请求,将其替换:id
为待办事项id
要创建新的待办事项,请在请求正文中向 发出POST
请求。localhost:8000/api/todos
title: <String>
好的。让我们检查一下待办事项是否创建成功。再次
发送GET
请求以localhost:8000/api/todos
获取所有待办事项。
耶!!!🤩
现在,让我们通过在请求正文中发送带有或或两者的PUT
请求来更新待办事项。 这里用 todo替换localhost:8000/api/todos/:id
title: <String>
completed: <Boolean>
:id
id
要删除待办事项,请发出DELETE
请求,localhost:8000/api/todos/:id
此处:id
用待办事项替换id
Congooooooo 🥳 🥳 🥳 我们做到了 💪🏻
结论
欲了解更多信息,我建议深入了解此处的文档https://docs.gofiber.io/
这是该项目的 GitHub 链接 - https://github.com/devsmranjan/golang-fiber-basic-todo-app
谢谢你阅读我的文章 🙂 。希望你在这里有所收获。
祝您编码愉快👨💻👩💻,请继续关注本系列的下一篇文章!
谢谢!别忘了点个♥️并关注我哦 :)
文章来源:https://dev.to/devsmranjan/golang-build-your-first-rest-api-with-fibre-24eh