对于使用 InterSystems IRIS 的 Go 开发人员来说,我们已经达到了两个重要的里程碑:
现在是时候看看一切如何协同工作了。
为了演示 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-app
2.下载依赖项并生成 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
func TestDB(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),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Error,
Colorful: true,
},
)
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
}
func DropTestDB() error {
if container != nil {
container.Terminate(context.Background())
}
container = nil
return nil
}
func AutoMigrate(db *gorm.DB) {
db.AutoMigrate(
&model.User{},
&model.Follow{},
&model.Article{},
&model.Comment{},
&model.Tag{},
)
}
使用容器化 IRIS 在 cli 标志下设置,并在 handler_test.go 文件中设置
var (
useContainer bool
)
func TestMain(m *testing.M) {
flag.BoolVar(&useContainer, "container", true, "Use container image.")
flag.Parse()
code := m.Run()
os.Exit(code)
}
func setup() {
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.360s
5.使用 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 测试套件。
如果一切设置正确,你应该会看到如下摘要:
[+] 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 生态系统中的一等公民--功能强大、速度快,并可用于云计算。
功能强大、速度快,可用于云原生应用程序。
该项目正在参与竞赛,请在此投票。