文章 Kelly Huang · 十一月 11, 2025 31m read

将一切结合在一起:Go、GORM 和 InterSystems IRIS 的实际应用

对于使用 InterSystems IRIS 的 Go 开发人员来说,我们已经达到了两个重要的里程碑:

现在是时候看看一切如何协同工作了。

为了演示 Go 开发人员可以如何轻松地采用 InterSystems IRIS,我使用了一个现有的生产级开源项目——RealWorld 示例应用程序——它展示了使用Go FiberGORMSQLite 实现的 Medium.com 式全栈克隆。

RealWorld Example App

只需稍作配置调整,我就将 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

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()
}

工作原理

  • useContainertrue 时,函数会通过 testcontainers-iris-go 启动一个新的 IRIS 容器。
    • 它将创建一个带有自定义凭据(testuser / testpassword)和名为 TEST 的命名空间的干净环境。
    • 连接字符串通过 container.MustConnectionString(ctx) 自动获取。
  • 在本地运行而不使用容器时,代码会连接到预先存在的 IRIS 实例,并确保在测试运行前重新创建 TEST 数据库。
  • AutoMigrate()会使用项目中定义的模型(UserArticleComment 等)自动创建所有需要的表。

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 应用程序。

这样,你就有了一个自足的容器——一个能同时运行IRISGo Web API的单一镜像,两者完全同步。


构建并启动应用程序

要构建 IRIS 映像并启动环境,只需运行

docker compose up -d iris --build

这将

  1. 构建 Go 应用程序。
  2. 创建一个新的基于 IRIS 的 Docker 映像,其中包含应用程序二进制文件和初始化脚本。
  3. 以分离模式 (-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

这将

  1. 启动Newman容器。
  2. 将其连接到运行中的 iris 服务。
  3. 针对 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后端提供支持,并通过GORMInterSystems IRIS 相连。

从这里,您可以

  • 注册和登录用户
  • 创建、编辑和删除文章
  • 发表评论
  • 关注或取消关注用户

通过新的 Go 驱动程序和 ORM 集成,IRIS 可实时处理您发送的所有请求。

下一步计划

您现在已经构建并运行了一个完整的Go + Fiber + GORM + IRIS后端--包括自动化测试、Swagger 文档和容器化部署。
自动化测试、Swagger 文档和容器化部署。

从这里,您可以

  • 用自己的功能扩展应用程序。
  • 将 IRIS 和 Go 应用程序作为单独的服务部署,以提高可扩展性。
  • 尝试使用高级 IRIS 功能--全局、分析和互操作性。

该演示表明,InterSystems IRIS可以成为现代 Go 生态系统中的一等公民--功能强大、速度快,并可用于云计算。
功能强大、速度快,可用于云原生应用程序。


该项目正在参与竞赛,请在此投票。