Skip to content

Commit e7d2f4f

Browse files
authored
feat: add openapi sample (#1063)
* feat: add openapi sample * fix fmt * panic * fix ci * add doc
1 parent 29a1565 commit e7d2f4f

13 files changed

Lines changed: 1842 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ Please refer to [HOWTO.md](HOWTO.md) for detailed instructions on running the sa
6464
* `rpc/grpc`: gRPC protocol example.
6565
* `rpc/jsonrpc`: JSON-RPC protocol example.
6666
* `rpc/triple`: Triple protocol example with multiple serialization formats.
67+
* `rpc/triple/openapi`: Demonstrates how to enable OpenAPI documentation for Triple protocol services, including versioned services and non-IDL services.
6768
* `streaming`: Streaming RPC example, also includes Go–Java interoperability when both use streaming.
6869
* `task`: Task scheduling and execution example.
6970
* `timeout`: Demonstrates timeout handling in Dubbo-go.

README_CN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
* `rpc/grpc`:基于 gRPC 协议的示例。
6565
* `rpc/jsonrpc`:基于 JSON-RPC 协议的示例。
6666
* `rpc/triple`:Triple 协议示例,涵盖多种序列化方式。
67+
* `rpc/triple/openapi`:演示如何为 Triple 协议服务启用 OpenAPI 文档,包括多版本服务和非 IDL 服务的注册。
6768
* `streaming`:流式 RPC 调用示例,并包含了Dubbo-go与Dubbo-java同时使用流式传输的互操作示例。
6869
* `task`:任务调度与执行示例。
6970
* `timeout`:Dubbo-go 超时处理示例。

rpc/triple/openapi/README.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Triple OpenAPI Sample
2+
3+
English | [中文](README_CN.md)
4+
5+
This sample demonstrates how to enable OpenAPI documentation for Triple protocol services in Dubbo-go. With OpenAPI enabled, the Triple server automatically generates and serves OpenAPI documentation in both JSON and YAML formats, and provides built-in Swagger UI and ReDoc pages for easy browsing and testing of your RPC services.
6+
7+
## What It Covers
8+
9+
- Enabling OpenAPI via `triple.OpenAPIEnable()` inside `triple.WithOpenAPI()`.
10+
- Registering multiple proto-based services (including streaming) with OpenAPI support.
11+
- Registering services with different versions and OpenAPI groups.
12+
- Registering a non-proto (non-IDL) service alongside proto-based services.
13+
14+
## Contents
15+
16+
- `go-server/cmd/main.go` - The server that enables OpenAPI and registers multiple services.
17+
- `go-client/cmd/main.go` - The client that calls the greet service (unary, server stream, client stream, bidi stream).
18+
- `proto/greet/greet.proto` - Protobuf definition with unary and streaming RPCs.
19+
- `proto/demo/demo.proto` - Protobuf definition for demonstrating versioned service registration.
20+
21+
## How to Run
22+
23+
### Start the Server
24+
25+
```shell
26+
go run ./go-server/cmd/main.go
27+
```
28+
29+
### Verify OpenAPI Documentation
30+
31+
Once the server is running, you can access the OpenAPI documentation via the following URLs:
32+
33+
| URL | Description |
34+
|-----|-------------|
35+
| `http://127.0.0.1:20000/dubbo/openapi/swagger-ui/` | Swagger UI page |
36+
| `http://127.0.0.1:20000/dubbo/openapi/openapi.json` | OpenAPI spec in JSON format |
37+
| `http://127.0.0.1:20000/dubbo/openapi/openapi.yaml` | OpenAPI spec in YAML format |
38+
| `http://127.0.0.1:20000/dubbo/openapi/api-docs/default.json` | Per-group OpenAPI spec (JSON) for the `default` group |
39+
| `http://127.0.0.1:20000/dubbo/openapi/api-docs/default.yaml` | Per-group OpenAPI spec (YAML) for the `default` group |
40+
| `http://127.0.0.1:20000/dubbo/openapi/redoc/index.html?group=default` | ReDoc documentation for the `default` group |
41+
42+
For the `demo-2.0.0` group, replace `default` with `demo-2.0.0` in the URLs above.
43+
44+
### Run the Client
45+
46+
```shell
47+
go run ./go-client/cmd/main.go
48+
```
49+
50+
## Configuration Reference
51+
52+
### Server-side OpenAPI Configuration
53+
54+
`triple.WithOpenAPI()` is the entry point for OpenAPI configuration. It accepts the following options:
55+
56+
| Option | Description | Default |
57+
|--------|-------------|---------|
58+
| `triple.OpenAPIEnable()` | Enable OpenAPI documentation generation. **Required** to activate OpenAPI. | `false` |
59+
| `triple.OpenAPIInfoTitle(title)` | Title of the OpenAPI document. | `"Dubbo-go OpenAPI"` |
60+
| `triple.OpenAPIInfoDescription(desc)` | Description of the OpenAPI document. | `"Dubbo-go OpenAPI"` |
61+
| `triple.OpenAPIInfoVersion(version)` | Version of the OpenAPI document. | `"1.0.0"` |
62+
| `triple.OpenAPIPath(path)` | Base URL path for serving OpenAPI endpoints. | `"/dubbo/openapi"` |
63+
| `triple.OpenAPIDefaultConsumesMediaTypes(types...)` | Default request content types. | `["application/json"]` |
64+
| `triple.OpenAPIDefaultProducesMediaTypes(types...)` | Default response content types. | `["application/json"]` |
65+
| `triple.OpenAPIDefaultHttpStatusCodes(codes...)` | Default HTTP status codes for responses. | `["200", "400", "500"]` |
66+
| `triple.OpenAPISettings(settings)` | Additional key-value settings. | `{}` |
67+
68+
Example:
69+
70+
```go
71+
srv, err := server.NewServer(
72+
server.WithServerProtocol(
73+
protocol.WithTriple(
74+
triple.WithOpenAPI(
75+
triple.OpenAPIEnable(),
76+
triple.OpenAPIInfoTitle("OpenAPI Service"),
77+
triple.OpenAPIInfoDescription("A service with OpenAPI documentation"),
78+
triple.OpenAPIInfoVersion("1.0.0"),
79+
),
80+
),
81+
protocol.WithPort(20000),
82+
),
83+
)
84+
```
85+
86+
### Service-level OpenAPI Group
87+
88+
When registering a service, you can assign it to a specific OpenAPI group via `server.WithOpenAPIGroup()`:
89+
90+
```go
91+
demo.RegisterGreetServiceHandler(srv, &DemoTripleServerV2{},
92+
server.WithOpenAPIGroup("demo-2.0.0"),
93+
server.WithVersion("2.0.0"),
94+
)
95+
```
96+
97+
Services without an explicit group fall into the `default` group.
98+
99+
### Services Registered in This Sample
100+
101+
| Service | Description |
102+
|---------|-------------|
103+
| `greet.GreetService` | Unary + streaming RPCs (server stream, client stream, bidi stream) |
104+
| `demo.GreetService` (v1.0.0) | Unary RPC with version `1.0.0` |
105+
| `demo.GreetService` (v2.0.0) | Same interface with version `2.0.0`, registered under OpenAPI group `demo-2.0.0` |
106+
| `com.example.UserService` | Non-proto (non-IDL) service, registered without protobuf |

rpc/triple/openapi/README_CN.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Triple OpenAPI 示例
2+
3+
[English](README.md) | 中文
4+
5+
本示例演示如何在 Dubbo-go 中为 Triple 协议服务启用 OpenAPI 文档。启用 OpenAPI 后,Triple 服务端会自动生成并提供 JSON 和 YAML 两种格式的 OpenAPI 文档,同时内置 Swagger UI 和 ReDoc 页面,方便浏览和测试 RPC 服务。
6+
7+
## 功能说明
8+
9+
- 通过 `triple.OpenAPIEnable()``triple.WithOpenAPI()` 中启用 OpenAPI 文档。
10+
- 注册多个基于 Protobuf 的服务(包括流式 RPC),并支持 OpenAPI 文档。
11+
- 注册不同版本的服务,并使用不同的 OpenAPI 分组。
12+
- 在基于 Protobuf 的服务之外,注册非 Protobuf(非 IDL)的服务。
13+
14+
## 目录结构
15+
16+
- `go-server/cmd/main.go` - 启用 OpenAPI 并注册多个服务的服务端。
17+
- `go-client/cmd/main.go` - 调用 Greet 服务的客户端(Unary、Server Stream、Client Stream、Bidi Stream)。
18+
- `proto/greet/greet.proto` - 包含 Unary 和流式 RPC 的 Protobuf 定义。
19+
- `proto/demo/demo.proto` - 用于演示多版本服务注册的 Protobuf 定义。
20+
21+
## 运行方法
22+
23+
### 启动服务端
24+
25+
```shell
26+
go run ./go-server/cmd/main.go
27+
```
28+
29+
### 验证 OpenAPI 文档
30+
31+
服务启动后,可以通过以下地址访问 OpenAPI 文档:
32+
33+
| URL | 说明 |
34+
|-----|------|
35+
| `http://127.0.0.1:20000/dubbo/openapi/swagger-ui/` | Swagger UI 页面 |
36+
| `http://127.0.0.1:20000/dubbo/openapi/openapi.json` | JSON 格式的 OpenAPI 规范 |
37+
| `http://127.0.0.1:20000/dubbo/openapi/openapi.yaml` | YAML 格式的 OpenAPI 规范 |
38+
| `http://127.0.0.1:20000/dubbo/openapi/api-docs/default.json` | `default` 分组的 OpenAPI 规范(JSON) |
39+
| `http://127.0.0.1:20000/dubbo/openapi/api-docs/default.yaml` | `default` 分组的 OpenAPI 规范(YAML) |
40+
| `http://127.0.0.1:20000/dubbo/openapi/redoc/index.html?group=default` | `default` 分组的 ReDoc 文档 |
41+
42+
对于 `demo-2.0.0` 分组,将上述 URL 中的 `default` 替换为 `demo-2.0.0` 即可。
43+
44+
### 启动客户端
45+
46+
```shell
47+
go run ./go-client/cmd/main.go
48+
```
49+
50+
## 配置说明
51+
52+
### 服务端 OpenAPI 配置
53+
54+
`triple.WithOpenAPI()` 是 OpenAPI 配置的入口,接受以下选项:
55+
56+
| 选项 | 说明 | 默认值 |
57+
|------|------|--------|
58+
| `triple.OpenAPIEnable()` | 启用 OpenAPI 文档生成,**必须调用**才能激活 OpenAPI。 | `false` |
59+
| `triple.OpenAPIInfoTitle(title)` | OpenAPI 文档标题。 | `"Dubbo-go OpenAPI"` |
60+
| `triple.OpenAPIInfoDescription(desc)` | OpenAPI 文档描述。 | `"Dubbo-go OpenAPI"` |
61+
| `triple.OpenAPIInfoVersion(version)` | OpenAPI 文档版本。 | `"1.0.0"` |
62+
| `triple.OpenAPIPath(path)` | OpenAPI 端点的 URL 基础路径。 | `"/dubbo/openapi"` |
63+
| `triple.OpenAPIDefaultConsumesMediaTypes(types...)` | 默认请求内容类型。 | `["application/json"]` |
64+
| `triple.OpenAPIDefaultProducesMediaTypes(types...)` | 默认响应内容类型。 | `["application/json"]` |
65+
| `triple.OpenAPIDefaultHttpStatusCodes(codes...)` | 默认响应 HTTP 状态码。 | `["200", "400", "500"]` |
66+
| `triple.OpenAPISettings(settings)` | 额外的键值对配置。 | `{}` |
67+
68+
示例:
69+
70+
```go
71+
srv, err := server.NewServer(
72+
server.WithServerProtocol(
73+
protocol.WithTriple(
74+
triple.WithOpenAPI(
75+
triple.OpenAPIEnable(),
76+
triple.OpenAPIInfoTitle("OpenAPI Service"),
77+
triple.OpenAPIInfoDescription("A service with OpenAPI documentation"),
78+
triple.OpenAPIInfoVersion("1.0.0"),
79+
),
80+
),
81+
protocol.WithPort(20000),
82+
),
83+
)
84+
```
85+
86+
### 服务级 OpenAPI 分组
87+
88+
注册服务时,可以通过 `server.WithOpenAPIGroup()` 将服务分配到指定的 OpenAPI 分组:
89+
90+
```go
91+
demo.RegisterGreetServiceHandler(srv, &DemoTripleServerV2{},
92+
server.WithOpenAPIGroup("demo-2.0.0"),
93+
server.WithVersion("2.0.0"),
94+
)
95+
```
96+
97+
未显式指定分组的服务会归入 `default` 分组。
98+
99+
### 本示例注册的服务
100+
101+
| 服务 | 说明 |
102+
|------|------|
103+
| `greet.GreetService` | Unary + 流式 RPC(Server Stream、Client Stream、Bidi Stream) |
104+
| `demo.GreetService` (v1.0.0) | 版本为 `1.0.0` 的 Unary RPC |
105+
| `demo.GreetService` (v2.0.0) | 相同接口但版本为 `2.0.0`,注册在独立的 OpenAPI 分组 `demo-2.0.0`|
106+
| `com.example.UserService` | 非 Protobuf(非 IDL)服务,不依赖 Protobuf 定义 |
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package main
19+
20+
import (
21+
"context"
22+
"fmt"
23+
"strings"
24+
)
25+
26+
import (
27+
"dubbo.apache.org/dubbo-go/v3/client"
28+
_ "dubbo.apache.org/dubbo-go/v3/imports"
29+
)
30+
31+
import (
32+
greet "github.com/apache/dubbo-go-samples/rpc/triple/openapi/proto/greet"
33+
)
34+
35+
func main() {
36+
cli, err := client.NewClient(
37+
client.WithClientURL("127.0.0.1:20000"),
38+
)
39+
if err != nil {
40+
panic(err)
41+
}
42+
svc, err := greet.NewGreetService(cli)
43+
if err != nil {
44+
panic(err)
45+
}
46+
47+
// Unary
48+
resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: "openapi"})
49+
if err != nil {
50+
panic(err)
51+
}
52+
fmt.Printf("Greet response: %s\n", resp.Greeting)
53+
54+
// Server Stream
55+
serverStream, err := svc.GreetServerStream(context.Background(), &greet.GreetServerStreamRequest{Name: "openapi"})
56+
if err != nil {
57+
panic(err)
58+
}
59+
for serverStream.Recv() {
60+
msg := serverStream.Msg()
61+
fmt.Printf("GreetServerStream response: %s\n", msg.Greeting)
62+
}
63+
64+
// Client Stream
65+
clientStream, err := svc.GreetClientStream(context.Background())
66+
if err != nil {
67+
panic(err)
68+
}
69+
for _, name := range []string{"alice", "bob", "charlie"} {
70+
if sendErr := clientStream.Send(&greet.GreetClientStreamRequest{Name: name}); sendErr != nil {
71+
panic(sendErr)
72+
}
73+
}
74+
clientResp, err := clientStream.CloseAndRecv()
75+
if err != nil {
76+
panic(err)
77+
}
78+
fmt.Printf("GreetClientStream response: %s\n", clientResp.Greeting)
79+
80+
// Bidi Stream
81+
bidiStream, err := svc.GreetBidiStream(context.Background())
82+
if err != nil {
83+
panic(err)
84+
}
85+
for _, name := range []string{"dave", "eve"} {
86+
if err := bidiStream.Send(&greet.GreetBidiStreamRequest{Name: name}); err != nil {
87+
panic(err)
88+
}
89+
}
90+
if err := bidiStream.CloseRequest(); err != nil {
91+
panic(err)
92+
}
93+
for {
94+
msg, err := bidiStream.Recv()
95+
if err != nil && strings.Contains(err.Error(), "EOF") {
96+
break
97+
}
98+
if err != nil {
99+
panic(err)
100+
}
101+
fmt.Printf("GreetBidiStream response: %s\n", msg.Greeting)
102+
}
103+
}

0 commit comments

Comments
 (0)