使用 Golang 编写简单的 REST API
让我们这样做👍🏻
你好😀
在这篇简短的文章中,我将解释如何使用Golang编写REST API并尝试遵循一些最佳实践。
如果需要的话,可以参考这里的源代码。
让我们这样做👍🏻
作为示例,我们将创建一个非常简单的 Post API。
项目结构
让我们跳转到我们的终端并为我们的项目创建一个新目录,然后初始化一个 go 模块。
mkdir postapi
cd postapi
go mod init postapi
注意:模块命名的最佳实践是使用<domain>/<nameOfApp>
现在我们有了这些,让我们用我们最喜欢的代码编辑器打开我们的项目,并创建一个main.go
带有 main 包的文件。这将是我们应用程序的入口点。
接下来,创建一个包含文件的包应用程序app.go
在其中,我们将创建一个 App 结构体来表示我们应用的结构。这个结构体包含两个字段:DB和Router。
路由器将使用gorilla/mux路由器,因此我们先导入它:
go get -u github.com/gorilla/mux
现在我们将创建一个New()函数,它将负责根据我们的结构返回实际的应用程序。
现在main.go
我们可以在我们的文件中调用此函数并创建一个新的应用程序。
好的,应用程序的入口点已经结构化,让我们继续进行路由。
路由
让我们使用之前定义的App的Router来实现基本的路由。 在我们的文件中,我们将创建一个InitRoutes函数,它将在创建应用程序时在New()函数内部被调用。这个函数将成为我们App的接收器。实际上,从现在开始,我们的很多方法都将成为应用程序的接收器。由于结构体App中的 Router 字段属于gorilla/mux router 类型,因此我们可以访问它的方法。app.go
让我们快速地用一个简单的处理程序来替换索引路由中的nil。为此,handlers.go
在我们的 app 包中创建一个文件。我们将在这里存储路由的处理程序。我将创建一个IndexHandler()处理程序,它将返回一个http.HandlerFunc函数,打印“Welcome to Post API”的响应。
完美,为了测试一下,我们需要回到文件,main.go
在我们选择的端口上为应用程序提供服务,并将其重定向到我们的应用程序 Router。此外,我还创建了一个检查函数来打印错误处理的帮助信息。
好的,现在我们可以运行我们的应用程序go run main.go
并卷曲端点以查看是否得到响应。
curl http://localhost:9000
太棒了,路由似乎正在起作用!
数据库
现在是时候设置我们的数据库了,我选择使用PostgreSQL,为了避免本地设置,我将在Docker容器上运行我的数据库。
我将使用以下命令:
docker run --name postapidb --env POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres
注意:要停止,您只需运行docker stop postapidb
并删除它docker rm postapidb
好的,现在我们已经有一个正在运行的数据库,让我们跳转到代码并在我们的应用程序包内创建一个新的包数据库。
让我们创建一个db.go
文件,并在其中添加一个接口。我将其命名为PostDB
。这个接口就像一个契约(需要实现的方法),如果我们想将数据库用作PostDB数据库,就必须遵守它。首先,PostDB应该实现一个Open()和一个Close( )方法,这两个方法可以返回错误。
我们还将创建一个类似于我们应用程序的DB结构,其中包含一个类型为sqlx DB的字段 db,该字段类似于Go 标准库中database/sql的超集。让我们运行 go get 命令获取sqlx和lib/pq(postgres sql 驱动程序),然后实现它。
go get -u github.com/jmoiron/sqlx
go get -u github.com/lib/pq
现在,在编写Open()和Close()函数主体之前,我们可以向 App 结构体中添加一个数据库字段,以app.go
表明我们在此应用程序中使用PostDB 🙂
接下来,从我们的Open方法开始,让我们打开一个到我们的 postgres 数据库的新连接。
为了建立此连接, sqlx.Open()方法的第二个参数是一个 Postgres 连接字符串。让我们在数据库config.go
包中名为 still的单独文件中构建此字符串。
我还想创建一个 SQL 模式,用于在连接后运行。如果数据库中没有 posts 表,该模式会创建一个。我们把它添加到一个schemas.go
文件中。
我们的Close方法会简单很多。我们只需要从sqlx调用 Close 方法即可。
在为我们的数据编写一些方法之前,让我们跳转到main.go
文件并初始化与数据库的连接。
让我们奔跑吧go run main.go
数据库已配置但尚未完全完成,因为我想实现一些方法(如 CreatePost 和 GetPosts),但为此我们首先需要一个Post模型。
模型
继续在app包中创建一个新的包models,并创建一个文件。在文件里面,我们将创建一个包含 4 个字段的Post结构体。post.go
由于这是一个 REST API,我们稍后会将响应映射到 JSON,有时数据库中的字段可能与 JSON 字段不对应,或者我们可能希望灵活地添加新字段或删除字段。
为此,我们先在文件中创建一个JsonPost结构体。
最后我想在这个文件中添加的内容几秒钟后就会用到。当我们将帖子添加到数据库时,ID 会自动递增,这意味着我们在创建新帖子的请求时无需传递 ID。因此,让我们为此创建一个PostRequest结构体。
回到我们文件中的数据库,我想向我的PostDBdb.go
接口添加 2 个方法,GetPosts和CreatePost。
注意:我不会实现所有的 REST 动词端点(尽量保持简短),只是简单的 GET 和 POST。
在我们的文件中,我想为我的CreatePostschemas.go
方法添加一个简单的insertPostSchema。
让我们创建一个methods.go
文件并编写我们的方法。
Http 处理程序
现在我们已经有了与数据库交互的所有方法,让我们像之前为IndexHandler编写 http 处理程序一样。在我们的handlers.go
文件中,让我们从CreatePostHandler开始。
我们要做的是初始化一个空的PostRequest结构体,然后解析用户输入的请求体到该结构体中。为了解析或映射请求体,我将编写一个名为parse的辅助函数,并将其放入一个helpers.go
文件中。
再次强调,这是一个REST API,因此发送 http 状态是个好习惯。我们接下来会发送很多带有 http 状态的响应,所以我会在文件中为此编写另一个辅助函数,helpers.go
用于发送带有状态的 JSON 响应。
顺便说一下,还记得我们之前有个JsonPost结构体,方便我们灵活使用吗?我们最后添加一个辅助函数 ( helpers.go
),用来将数据映射到该结构体。
继续使用CreatePostHandler,现在我们已经解析了请求主体,我们需要使用该数据来创建新帖子并将其保存在我们的数据库中。
现在要完成CreatePostHandler,我们只需要在我们的文件中的func initRoutesapp.go
中创建一个新路由并调用我们的处理程序。
再次运行并让我们在Insomniago run main.go
上进行测试。
似乎有效👍🏻
在进行测试之前,让我们先实现更简单的GetPostHandler 。
完美,一切正常 🙂
测试
测试代码也是非常好的做法,因此我们需要尝试为应用添加测试覆盖率。为此,您可以创建一个测试包,并添加要测试的测试文件,例如handler_test.go
或db_test.go
。
我实际上制作了一个视频并写了一篇关于在 Golang 中实现测试的文章,所以你可以查看一下 🙂
结论
就这样!这篇文章就写到这里吧,我知道还有改进的空间,但我想长话短说,只谈一下基础。
与往常一样,不要犹豫给我反馈,当今开发人员的角色是不断改进,这就是我想要做的🙂
请随时查看我的Youtube 频道,您也可以通过我的Twitter 帐户联系我,当然我会链接本文的GitHub 存储库。
很快再见!👋🏻
文章来源:https://dev.to/lucasnevespereira/write-a-rest-api-in-golang-following-best-practices-pe9