将一切结合在一起:Go、GORM 和 InterSystems IRIS 的实际应用
对于使用 InterSystems IRIS 的 Go 开发人员来说,我们已经达到了两个重要的里程碑:
- 终于等到你:欢迎了解 InterSystems IRIS对GoLang 的支持——我们发布了新的go-irisnative驱动程序,为 Go 提供了本地
database/sql接口。 - GORM 与 InterSystems IRIS 的相遇:介绍一下 gorm-iris—— 我们在这里展示了如何将 IRIS 与GORM 集成,GORM 是最流行的 Go ORM 库之一。
现在是时候看看一切如何协同工作了。
为了演示 Go 开发人员可以如何轻松地采用 InterSystems IRIS,我使用了一个现有的生产级开源项目——RealWorld 示例应用程序——它展示了使用Go Fiber、GORM 和SQLite 实现的 Medium.com 式全栈克隆。

只需稍作配置调整,我就将 SQLite 换成了gorm-iris,其他一切保持不变。结果如何?
一个由 InterSystems IRIS 支持的功能齐全的 Go + Fiber 应用程序——不需要重写代码,不需要 ORM 体操,只需要一个不同的数据库后端。
您可以在这里找到完整的工作演示:github.com/caretdev/golang-fiber-iris-realworld-example-app
开始使用
让我们运行演示项目。
1.克隆项目
git clone git@github.com:caretdev/golang-fiber-iris-realworld-example-app.git
cd golang-fiber-iris-realworld-example-app2.下载依赖项并生成 Swagger 文档
安装 Go 依赖项并生成 API 文档:
go mod download
go install github.com/swaggo/swag/cmd/swag@latest
go generate .这将
- 下载所有需要的 Go 模块。
- 安装用于生成 Swagger 文档的
swag工具。 - 执行 Go
generate命令,根据代码库中的注释重建 Swagger 定义。
运行该命令后,您将在 docs/ 目录下看到生成的文档文件。
3.数据库设置和测试
该项目包含一个 db.go 文件,其中定义了初始化数据库连接的逻辑。
为了简化测试并确保环境整洁,我们使用了testcontainers-iris-go——它会为每次测试运行启动一个全新的 InterSystems IRIS 容器。
这意味着每次测试都从一个空的、隔离的 IRIS 实例开始,是可靠的自动测试的理想选择。
以下是实现该功能的核心代码部分:
var container *iriscontainer.IRISContainer
funcTestDB(useContainer bool) *gorm.DB {
var err error
var connectionString = "iris://_SYSTEM:SYS@localhost:1972/USER"if useContainer {
options := []testcontainers.ContainerCustomizer{
iriscontainer.WithNamespace("TEST"),
iriscontainer.WithUsername("testuser"),
iriscontainer.WithPassword("testpassword"),
}
ctx := context.Background()
container, err = iriscontainer.RunContainer(ctx, options...)
if err != nil {
log.Println("Failed to start container:", err)
os.Exit(1)
}
connectionString = container.MustConnectionString(ctx)
fmt.Println("Container started: ", connectionString)
}
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
SlowThreshold: time.Second, // Slow SQL threshold
LogLevel: logger.Error, // Log level
Colorful: true, // Disable color
},
)
db, err := gorm.Open(iris.New(iris.Config{
DSN: connectionString,
}), &gorm.Config{
Logger: newLogger,
})
if !useContainer {
_ = db.Exec("DROP DATABASE TEST").Error
_ = db.Exec("CREATE DATABASE TEST").Error
_ = db.Exec("USE DATABASE TEST").Error
}
if err != nil {
fmt.Println("storage err: ", err)
}
return db
}
funcDropTestDB()error {
if container != nil {
container.Terminate(context.Background())
}
container = nilreturnnil
}
funcAutoMigrate(db *gorm.DB) {
db.AutoMigrate(
&model.User{},
&model.Follow{},
&model.Article{},
&model.Comment{},
&model.Tag{},
)
}使用容器化 IRIS 在 cli 标志下设置,并在 handler_test.go 文件中设置
var (
useContainer bool
)
funcTestMain(m *testing.M) {
flag.BoolVar(&useContainer, "container", true, "Use container image.")
flag.Parse()
// setup()
code := m.Run()
// tearDown()
os.Exit(code)
}
funcsetup() {
d = db.TestDB(useContainer)
db.AutoMigrate(d)
us = store.NewUserStore(d)
as = store.NewArticleStore(d)
h = NewHandler(us, as)
e = router.New()
loadFixtures()
}
工作原理
- 当
useContainer为true时,函数会通过testcontainers-iris-go启动一个新的 IRIS 容器。- 它将创建一个带有自定义凭据(
testuser/testpassword)和名为TEST的命名空间的干净环境。 - 连接字符串通过
container.MustConnectionString(ctx)自动获取。
- 它将创建一个带有自定义凭据(
- 在本地运行而不使用容器时,代码会连接到预先存在的 IRIS 实例,并确保在测试运行前重新创建
TEST数据库。 AutoMigrate()会使用项目中定义的模型(User、Article、Comment等)自动创建所有需要的表。
4.运行测试
数据库配置就绪后,就可以使用以下工具执行所有测试:
go test ./handler -v可以添加 -container 或 -container=0 标志来改变测试方式
此命令将
- 以冗长模式编译并运行所有 Go 测试。
- 为每个测试启动一个新的 IRIS 容器(如果启用)。
- 自动应用迁移并在完成后进行清理。
如果一切配置正确,你会看到类似以下的日志输出:
测试结果
=== RUN TestListArticlesCaseSuccess 2025/10/07 23:29:20 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:105 record not found
[22.836ms] [rows:0] SELECT * FROM "follows" WHERE following_id = 2 AND follower_id = 0 ORDER BY "follows"."follower_id" LIMIT 1 2025/10/07 23:29:20 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:105 record not found
[0.491ms] [rows:0] SELECT * FROM "follows" WHERE following_id = 1 AND follower_id = 0 ORDER BY "follows"."follower_id" LIMIT 1
23:29:20 | 200 | 112.944458ms | 0.0.0.0 | GET | /api/articles | -
--- PASS: TestListArticlesCaseSuccess (3.95s)
=== RUN TestGetArticlesCaseSuccess
23:29:23 | 200 | 28.764333ms | 0.0.0.0 | GET | /api/articles/article1-slug | -
--- PASS: TestGetArticlesCaseSuccess (3.79s)
=== RUN TestCreateArticleCaseSuccess
23:29:27 | 201 | 21.660834ms | 0.0.0.0 | POST | /api/articles | -
--- PASS: TestCreateArticleCaseSuccess (3.75s)
=== RUN TestUpdateArticleCaseSuccess 2025/10/07 23:29:31 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/article.go:85 record not found
[12.349ms] [rows:0] SELECT * FROM "tags" WHERE "tags"."tag" = 'tag3' AND "tags"."deleted_at" IS NULL ORDER BY "tags"."id" LIMIT 1
23:29:31 | 200 | 74.888416ms | 0.0.0.0 | PUT | /api/articles/article1-slug | -
--- PASS: TestUpdateArticleCaseSuccess (3.82s)
=== RUN TestFeedCaseSuccess
23:29:35 | 200 | 103.316875ms | 0.0.0.0 | GET | /api/articles/feed | -
--- PASS: TestFeedCaseSuccess (3.85s)
=== RUN TestDeleteArticleCaseSuccess
23:29:39 | 200 | 32.845667ms | 0.0.0.0 | DELETE | /api/articles/article1-slug | - 2025/10/07 23:29:39 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/article.go:38 record not found
[0.689ms] [rows:0] SELECT * FROM "articles" WHERE ("articles"."slug" = 'article1-slug' AND "articles"."author_id" = 1) AND "articles"."deleted_at" IS NULL ORDER BY "articles"."id" LIMIT 1
23:29:39 | 404 | 885.375µs | 0.0.0.0 | DELETE | /api/articles/article1-slug | -
--- PASS: TestDeleteArticleCaseSuccess (3.78s)
=== RUN TestGetCommentsCaseSuccess
23:29:42 | 200 | 31.516292ms | 0.0.0.0 | GET | /api/articles/article1-slug/comments | -
--- PASS: TestGetCommentsCaseSuccess (3.88s)
=== RUN TestAddCommentCaseSuccess
23:29:46 | 201 | 31.662291ms | 0.0.0.0 | POST | /api/articles/article1-slug/comments | -
--- PASS: TestAddCommentCaseSuccess (3.77s)
=== RUN TestDeleteCommentCaseSuccess
23:29:50 | 200 | 22.555375ms | 0.0.0.0 | DELETE | /api/articles/article1-slug/comments/1 | - 2025/10/07 23:29:50 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/article.go:254 record not found
[0.386ms] [rows:0] SELECT * FROM "comments" WHERE "comments"."id" = 1 AND "comments"."deleted_at" IS NULL ORDER BY "comments"."id" LIMIT 1
23:29:50 | 404 | 474.75µs | 0.0.0.0 | DELETE | /api/articles/article1-slug/comments/1 | -
--- PASS: TestDeleteCommentCaseSuccess (3.71s)
=== RUN TestFavoriteCaseSuccess
23:29:54 | 200 | 51.294125ms | 0.0.0.0 | POST | /api/articles/article1-slug/favorite | -
--- PASS: TestFavoriteCaseSuccess (3.80s)
=== RUN TestUnfavoriteCaseSuccess
23:29:58 | 200 | 44.780459ms | 0.0.0.0 | DELETE | /api/articles/article2-slug/favorite | -
--- PASS: TestUnfavoriteCaseSuccess (3.76s)
=== RUN TestGetTagsCaseSuccess
23:30:01 | 200 | 10.410208ms | 0.0.0.0 | GET | /api/tags | -
--- PASS: TestGetTagsCaseSuccess (3.71s)
=== RUN TestSignUpCaseSuccess
23:30:05 | 201 | 77.083166ms | 0.0.0.0 | POST | /api/users | -
--- PASS: TestSignUpCaseSuccess (3.79s)
=== RUN TestLoginCaseSuccess
23:30:09 | 200 | 89.146833ms | 0.0.0.0 | POST | /api/users/login | -
--- PASS: TestLoginCaseSuccess (3.87s)
=== RUN TestLoginCaseFailed 2025/10/07 23:30:13 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:33 record not found
[13.172ms] [rows:0] SELECT * FROM "users" WHERE "users"."email" = 'userx@realworld.io' AND "users"."deleted_at" IS NULL ORDER BY "users"."id" LIMIT 1
23:30:13 | 403 | 13.247833ms | 0.0.0.0 | POST | /api/users/login | -
--- PASS: TestLoginCaseFailed (3.74s)
=== RUN TestCurrentUserCaseSuccess
23:30:16 | 200 | 12.081041ms | 0.0.0.0 | GET | /api/user | -
--- PASS: TestCurrentUserCaseSuccess (3.75s)
=== RUN TestCurrentUserCaseInvalid 2025/10/07 23:30:20 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:22 record not found
[11.931ms] [rows:0] SELECT * FROM "users" WHERE "users"."id" = 100 AND "users"."deleted_at" IS NULL ORDER BY "users"."id" LIMIT 1
23:30:20 | 404 | 12.2145ms | 0.0.0.0 | GET | /api/user | -
--- PASS: TestCurrentUserCaseInvalid (3.74s)
=== RUN TestUpdateUserEmail
23:30:24 | 200 | 33.6815ms | 0.0.0.0 | PUT | /api/user | -
--- PASS: TestUpdateUserEmail (3.81s)
=== RUN TestUpdateUserMultipleField
23:30:28 | 200 | 43.375583ms | 0.0.0.0 | PUT | /api/user | -
--- PASS: TestUpdateUserMultipleField (3.75s)
=== RUN TestGetProfileCaseSuccess 2025/10/07 23:30:32 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:105 record not found
[17.585ms] [rows:0] SELECT * FROM "follows" WHERE following_id = 1 AND follower_id = 1 ORDER BY "follows"."follower_id" LIMIT 1
23:30:31 | 200 | 53.483292ms | 0.0.0.0 | GET | /api/profiles/user1 | -
--- PASS: TestGetProfileCaseSuccess (3.81s)
=== RUN TestGetProfileCaseNotFound 2025/10/07 23:30:35 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:44 record not found
[13.039ms] [rows:0] SELECT * FROM "users" WHERE "users"."username" = 'userx' AND "users"."deleted_at" IS NULL ORDER BY "users"."id" LIMIT 1
23:30:35 | 404 | 13.091583ms | 0.0.0.0 | GET | /api/profiles/userx | -
--- PASS: TestGetProfileCaseNotFound (3.72s)
=== RUN TestFollowCaseSuccess
23:30:39 | 200 | 57.295875ms | 0.0.0.0 | POST | /api/profiles/user2/follow | -
--- PASS: TestFollowCaseSuccess (3.84s)
=== RUN TestFollowCaseInvalidUser 2025/10/07 23:30:43 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:44 record not found
[13.084ms] [rows:0] SELECT * FROM "users" WHERE "users"."username" = 'userx' AND "users"."deleted_at" IS NULL ORDER BY "users"."id" LIMIT 1
23:30:43 | 404 | 13.191708ms | 0.0.0.0 | POST | /api/profiles/userx/follow | -
--- PASS: TestFollowCaseInvalidUser (3.75s)
=== RUN TestUnFollow 2025/10/07 23:30:47 /Users/daimor/Projects/golang-fiber-realworld-example-app/store/user.go:105 record not found
[15.231ms] [rows:0] SELECT * FROM "follows" WHERE following_id = 2 AND follower_id = 1 ORDER BY "follows"."follower_id" LIMIT 1
23:30:47 | 200 | 80.5655ms | 0.0.0.0 | DELETE | /api/profiles/user2/follow | -
--- PASS: TestUnFollow (3.82s)
PASS
ok github.com/alpody/fiber-realworld/handler 91.360s5.使用 Docker Compose 运行应用程序
确认测试成功通过后,下一步就是使用 Docker运行完整的 Fiber + GORM + IRIS 应用程序。
在此设置中,Go 后端被构建成二进制文件,复制到 IRIS 容器中,并与 IRIS 本身一起自动启动。
这种方法使部署变得极其简单——只需一条命令就能启动一切。
已更新 docker-compose.yml
该项目的修改版 docker-compose.yml 现在定义了一个iris 服务,可同时处理这两种情况:
- 运行InterSystems IRIS数据库。
- 作为同一容器的一部分启动Go Fiber 应用程序。
关键在于
- Go 应用程序使用多级 Docker 构建。
- 生成的二进制文件被复制到 IRIS 映像中。
- 其中包含一个小的init 脚本,用于在 IRIS 启动时自动启动 Go 应用程序。
这样,你就有了一个自足的容器——一个能同时运行IRIS和Go Web API的单一镜像,两者完全同步。
构建并启动应用程序
要构建 IRIS 映像并启动环境,只需运行
docker compose up -d iris --build这将
- 构建 Go 应用程序。
- 创建一个新的基于 IRIS 的 Docker 映像,其中包含应用程序二进制文件和初始化脚本。
- 以分离模式 (
-d) 启动容器,同时运行 IRIS 和 Go API。
💡注意:
Go的一个美妙之处在于,您不必局限于将应用程序嵌入 IRIS 容器。
得益于 Go 的单二进制编译,您可以轻松地为您的应用程序构建一个独立的 Docker 镜像,该镜像可以使用相同的连接字符串通过网络连接到 InterSystems IRIS。
这种方法有两大优势:
- 生成的映像更小,通常不到 30 MB。
- 它将应用逻辑与数据库基础架构干净利落地分离开来,是微服务或云部署的理想选择。
在生产过程中,你可以将 IRIS 和 Go 服务放在不同的容器(甚至不同的主机)中,通过网络安全地连接起来--将 IRIS 的可靠性和 Go 的可移植性结合起来。
6.使用 Newman 进行端到端 API 测试
Go + IRIS 应用程序启动并运行后,就需要验证 REST API 是否完全按照预期运行。
该项目包括一层额外的集成测试——使用原始 RealWorld 项目中的Postman / Newman集合。
这将确保后端完全符合 RealWorld API 规范,并确保所有端点在 InterSystems IRIS 支持下正常工作。
Newman即服务
为了实现无缝测试,docker-compose.yml 文件定义了一个名为newman-checker 的额外服务。
该服务在容器内运行Newman CLI,执行完整的 RealWorld API 测试集,并在内部连接到运行中的 Fiber + IRIS 应用程序。
由于这两个服务都在同一个 Docker 网络中运行,因此测试可以直接访问后端,无需任何额外配置。
运行 API 测试
要执行端到端测试,只需运行
docker compose run newman-checker这将
- 启动Newman容器。
- 将其连接到运行中的
iris服务。 - 针对 Go + IRIS 后端执行整个 RealWorld API 测试套件。
如果一切设置正确,你应该会看到如下摘要:
Newman测试结果
[+] Creating 1/1 ✔ Container golang-fiber-realworld-example-app-iris-1 Running 0.0s newman Conduit ❏ Auth ↳ Register POST http://iris:8585/api/users [201 Created, 327B, 202ms] ┌ │ 'Using "environment" is deprecated. Use "pm.environment" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "user" property ✓ User has "email" property ✓ User has "username" property ✓ User has "bio" property ✓ User has "image" property ✓ User has "token" property ↳ Login POST http://iris:8585/api/users/login [200 OK, 322B, 119ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "user" property ✓ User has "email" property ✓ User has "username" property ✓ User has "bio" property ✓ User has "image" property ✓ User has "token" property ↳ Login and Remember Token POST http://iris:8585/api/users/login [200 OK, 322B, 65ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "user" property ✓ User has "email" property ✓ User has "username" property ✓ User has "bio" property ✓ User has "image" property ✓ User has "token" property ✓ Global variable "token" has been set ↳ Current User GET http://iris:8585/api/user [200 OK, 322B, 20ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "user" property ✓ User has "email" property ✓ User has "username" property ✓ User has "bio" property ✓ User has "image" property ✓ User has "token" property ↳ Update User PUT http://iris:8585/api/user [200 OK, 318B, 16ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "user" property ✓ User has "email" property ✓ User has "username" property ✓ User has "bio" property ✓ User has "image" property ✓ User has "token" property ❏ Articles ↳ All Articles GET http://iris:8585/api/articles [200 OK, 141B, 29ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ articlesCount is 0 when feed is empty ↳ Articles by Author GET http://iris:8585/api/articles?author=johnjacob [200 OK, 141B, 2ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ articlesCount is 0 when feed is empty ↳ Articles Favorited by Username GET http://iris:8585/api/articles?favorited=user2021 [200 OK, 141B, 7ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ articlesCount is 0 when feed is empty ↳ Articles by Tag GET http://iris:8585/api/articles?tag=dragons [200 OK, 141B, 8ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ articlesCount is 0 when feed is empty ❏ Articles, Favorite, Comments ↳ Create Article POST http://iris:8585/api/articles [201 Created, 479B, 216ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "article" property ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "body" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ Feed GET http://iris:8585/api/articles/feed [200 OK, 141B, 14ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ articlesCount is 0 when feed is empty ↳ All Articles GET http://iris:8585/api/articles [200 OK, 495B, 28ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ All Articles with auth GET http://iris:8585/api/articles [200 OK, 495B, 3ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ Articles by Author GET http://iris:8585/api/articles?author=user2021 [200 OK, 495B, 4ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ Articles by Author with auth GET http://iris:8585/api/articles?author=user2021 [200 OK, 495B, 4ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ Single Article by slug GET http://iris:8585/api/articles/how-to-train-your-dragon [200 OK, 474B, 19ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "article" property ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "body" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ Articles by Tag GET http://iris:8585/api/articles?tag=dragons [200 OK, 495B, 3ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ An article was returned ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ The first tag is dragons ✓ The second tag is training ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ Update Article PUT http://iris:8585/api/articles/how-to-train-your-dragon [200 OK, 453B, 52ms] ┌ │ 'Using "environment" is deprecated. Use "pm.environment" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "article" property ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "body" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ↳ Favorite Article POST http://iris:8585/api/articles/how-to-train-your-dragon/favorite [200 OK, 454B, 51ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "article" property ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "body" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article's 'favorited' property is true ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ✓ Article's 'favoritesCount' property is greater than 0 ↳ Articles Favorited by Username GET http://iris:8585/api/articles?favorited=user2021 [200 OK, 470B, 3ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is 1 ↳ Articles Favorited by Username with auth GET http://iris:8585/api/articles?favorited=user2021 [200 OK, 470B, 4ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "articles" property ✓ Response contains "articlesCount" property ✓ articlesCount is an integer ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is 1 ↳ Unfavorite Article DELETE http://iris:8585/api/articles/how-to-train-your-dragon/favorite [200 OK, 449B, 13ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "article" property ✓ Article has "title" property ✓ Article has "slug" property ✓ Article has "body" property ✓ Article has "createdAt" property ✓ Article's "createdAt" property is an ISO 8601 timestamp ✓ Article has "updatedAt" property ✓ Article's "updatedAt" property is an ISO 8601 timestamp ✓ Article has "description" property ✓ Article has "tagList" property ✓ Article's "tagList" property is an Array ✓ Article has "author" property ✓ Article has "favorited" property ✓ Article has "favoritesCount" property ✓ favoritesCount is an integer ✓ Article's "favorited" property is false ↳ Create Comment for Article POST http://iris:8585/api/articles/how-to-train-your-dragon/comments [201 Created, 313B, 50ms] ┌ │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "comment" property ✓ Comment has "id" property ✓ Comment has "body" property ✓ Comment has "createdAt" property ✓ "createdAt" property is an ISO 8601 timestamp ✓ Comment has "updatedAt" property ✓ "updatedAt" property is an ISO 8601 timestamp ✓ Comment has "author" property ↳ All Comments for Article GET http://iris:8585/api/articles/how-to-train-your-dragon/comments [200 OK, 311B, 23ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "comments" property ✓ Comment has "id" property ✓ Comment has "body" property ✓ Comment has "createdAt" property ✓ "createdAt" property is an ISO 8601 timestamp ✓ Comment has "updatedAt" property ✓ "updatedAt" property is an ISO 8601 timestamp ✓ Comment has "author" property ↳ All Comments for Article without login GET http://iris:8585/api/articles/how-to-train-your-dragon/comments [200 OK, 311B, 2ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "comments" property ✓ Comment has "id" property ✓ Comment has "body" property ✓ Comment has "createdAt" property ✓ "createdAt" property is an ISO 8601 timestamp ✓ Comment has "updatedAt" property ✓ "updatedAt" property is an ISO 8601 timestamp ✓ Comment has "author" property ↳ Delete Comment for Article DELETE http://iris:8585/api/articles/how-to-train-your-dragon/comments/1 [200 OK, 123B, 27ms] ↳ Delete Article DELETE http://iris:8585/api/articles/how-to-train-your-dragon [200 OK, 123B, 15ms] ❏ Profiles ↳ Register Celeb POST http://iris:8585/api/users [201 Created, 339B, 65ms] ┌ │ 'Using "environment" is deprecated. Use "pm.environment" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response contains "user" property ✓ User has "email" property ✓ User has "username" property ✓ User has "bio" property ✓ User has "image" property ✓ User has "token" property ↳ Profile GET http://iris:8585/api/profiles/celeb_user2021 [200 OK, 191B, 30ms] ┌ │ 'Using "environment" is deprecated. Use "pm.environment" instead.' │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "profile" property ✓ Profile has "username" property ✓ Profile has "bio" property ✓ Profile has "image" property ✓ Profile has "following" property ↳ Follow Profile POST http://iris:8585/api/profiles/celeb_user2021/follow [200 OK, 190B, 32ms] ┌ │ 'Using "environment" is deprecated. Use "pm.environment" instead.' │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "profile" property ✓ Profile has "username" property ✓ Profile has "bio" property ✓ Profile has "image" property ✓ Profile has "following" property ✓ Profile's "following" property is true ↳ Unfollow Profile DELETE http://iris:8585/api/profiles/celeb_user2021/follow [200 OK, 191B, 47ms] ┌ │ 'Using "environment" is deprecated. Use "pm.environment" instead.' │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "profile" property ✓ Profile has "username" property ✓ Profile has "bio" property ✓ Profile has "image" property ✓ Profile has "following" property ✓ Profile's "following" property is false ❏ Tags ↳ All Tags GET http://iris:8585/api/tags [200 OK, 139B, 13ms] ┌ │ 'Using "responseCode" is deprecated. Use "pm.response.code" instead.' │ 'Using "tests" is deprecated. Use "pm.test()" instead.' └ ✓ Response code is 200 OK ✓ Response contains "tags" property ✓ "tags" property returned as array ┌─────────────────────────┬───────────────────┬──────────────────┐ │ │ executed │ failed │ ├─────────────────────────┼───────────────────┼──────────────────┤ │ iterations │ 1 │ 0 │ ├─────────────────────────┼───────────────────┼──────────────────┤ │ requests │ 32 │ 0 │ ├─────────────────────────┼───────────────────┼──────────────────┤ │ test-scripts │ 48 │ 0 │ ├─────────────────────────┼───────────────────┼──────────────────┤ │ prerequest-scripts │ 18 │ 0 │ ├─────────────────────────┼───────────────────┼──────────────────┤ │ assertions │ 311 │ 0 │ ├─────────────────────────┴───────────────────┴──────────────────┤ │ total run duration: 1824ms │ ├────────────────────────────────────────────────────────────────┤ │ total data received: 6.77kB (approx) │ ├────────────────────────────────────────────────────────────────┤ │ average response time: 37ms [min: 2ms, max: 216ms, s.d.: 50ms] │ └────────────────────────────────────────────────────────────────┘
这证实了什么
通过 Newman 套件意味着您的 Go + Fiber + GORM + IRIS 协议栈与 RealWorld API 规范完全兼容--这是一个很好的指标,表明您的后端逻辑、ORM 集成和数据库连接都能按预期运行。
这是一个很好的指标,表明您的后端逻辑、ORM 集成和数据库连接都能按预期运行。
这不再只是一个演示,而是一个由InterSystems IRIS 支持的符合规范的生产级后端。
7.使用 Swagger UI 探索应用程序接口
一切就绪并开始运行后,你终于可以通过一个简洁的交互式界面来探索实时 REST API 了。
该项目附带了一个预生成的 Swagger UI,可以直接在浏览器中轻松检查和测试端点。
启动应用程序后,打开
👉 http://localhost:8585/swagger/index.html
您将看到完整的 RealWorld API 规范 - 所有端点均由Go Fiber后端提供支持,并通过GORM与InterSystems IRIS 相连。
从这里,您可以
- 注册和登录用户
- 创建、编辑和删除文章
- 发表评论
- 关注或取消关注用户
通过新的 Go 驱动程序和 ORM 集成,IRIS 可实时处理您发送的所有请求。
.png)
下一步计划
您现在已经构建并运行了一个完整的Go + Fiber + GORM + IRIS后端--包括自动化测试、Swagger 文档和容器化部署。
自动化测试、Swagger 文档和容器化部署。
从这里,您可以
- 用自己的功能扩展应用程序。
- 将 IRIS 和 Go 应用程序作为单独的服务部署,以提高可扩展性。
- 尝试使用高级 IRIS 功能--全局、分析和互操作性。
该演示表明,InterSystems IRIS可以成为现代 Go 生态系统中的一等公民--功能强大、速度快,并可用于云计算。
功能强大、速度快,可用于云原生应用程序。
该项目正在参与竞赛,请在此投票。