Skip to content

Commit fc6be21

Browse files
authored
feat: migrate from gRPC to connectRPC (#182)
* feat: migrate from gRPC to connectRPC Replace gRPC server, gRPC-gateway, and associated middleware with connectRPC following the pattern established by Compass. This gives us native support for Connect, gRPC, and gRPC-Web protocols on a single HTTP port with standard net/http routing. Key changes: - buf.gen.yaml: switch to v2 with connectrpc/go plugin - Server: use http.ServeMux + connectRPC handler + h2c + CORS - API handlers: adopt connect.Request/Response generics - CLI client: use connectRPC client over plain HTTP - Middleware: add recovery, logger, error_response interceptors - Errors: replace GRPCStatus() with connect error codes - Config: remove GRPCConfig/NewRelic, add CORS config - Delete grpc-gateway, openapiv2, and custom validator packages * fix: include gen/buf/validate in generated code * fix: use remote buf/validate module, remove local gen/buf * fix: fetch proton from remote git repo instead of local directory * fix: move proton input to Makefile with configurable PROTON_REF * fix: pin proton commit in buf.gen.yaml instead of Makefile variable
1 parent d8b65a7 commit fc6be21

47 files changed

Lines changed: 3716 additions & 12268 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Makefile

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
NAME="github.com/raystack/stencil"
22
VERSION=$(shell git describe --always --tags 2>/dev/null)
3-
PROTON_COMMIT := "a6c7056fa80128145d00d5ee72f216c28578ec43"
43

54
.PHONY: all build test clean dist vet proto install ui
65

@@ -18,13 +17,12 @@ coverage: ui ## Print code coverage
1817
vet: ## Run the go vet tool
1918
go vet ./...
2019

21-
lint: ## Run golang-ci lint
20+
lint: ## Run golang-ci lint
2221
golangci-lint run
2322

2423
proto: ## Generate the protobuf files
2524
@echo " > generating protobuf from raystack/proton"
26-
@echo " > [info] make sure correct version of dependencies are installed using 'make install'"
27-
@buf generate https://github.com/raystack/proton/archive/${PROTON_COMMIT}.zip#strip_components=1 --template buf.gen.yaml --path raystack/stencil
25+
@buf generate
2826
@echo " > protobuf compilation finished"
2927

3028
clean: ## Clean the build artifacts
@@ -35,4 +33,4 @@ ui:
3533
@cd ui && $(MAKE) dep && $(MAKE) dist
3634

3735
help: ## Display this help message
38-
@cat $(MAKEFILE_LIST) | grep -e "^[a-zA-Z_\-]*: *.*## *" | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
36+
@cat $(MAKEFILE_LIST) | grep -e "^[a-zA-Z_\-]*: *.*## *" | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

buf.gen.yaml

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
version: v1
1+
version: v2
2+
inputs:
3+
- git_repo: https://github.com/raystack/proton.git
4+
ref: 8ef3e30859491f877a791fe0f9039370235c99b2
5+
paths:
6+
- raystack/stencil
7+
managed:
8+
enabled: true
9+
override:
10+
- file_option: go_package
11+
path: raystack/stencil/v1beta1/stencil.proto
12+
value: github.com/raystack/stencil/gen/raystack/stencil/v1beta1;stencilv1beta1
213
plugins:
3-
- name: go
4-
out: ./proto
5-
opt: paths=source_relative
6-
- name: go-grpc
7-
out: ./proto
8-
opt: paths=source_relative
9-
- remote: buf.build/raystack/plugins/validate
10-
out: "proto"
11-
opt: "paths=source_relative,lang=go"
12-
- name: grpc-gateway
13-
out: ./proto
14-
opt: paths=source_relative
15-
- name: openapiv2
16-
out: ./proto
17-
opt: "allow_merge=true"
14+
- remote: buf.build/protocolbuffers/go:v1.36.11
15+
out: gen
16+
opt:
17+
- paths=source_relative
18+
- remote: buf.build/connectrpc/go:v1.18.1
19+
out: gen
20+
opt:
21+
- paths=source_relative

cmd/check.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,18 @@ package cmd
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"os"
87

8+
"connectrpc.com/connect"
99
"github.com/MakeNowJust/heredoc"
1010
"github.com/raystack/salt/cli/printer"
11-
stencilv1beta1 "github.com/raystack/stencil/proto/raystack/stencil/v1beta1"
11+
stencilv1beta1 "github.com/raystack/stencil/gen/raystack/stencil/v1beta1"
1212
"github.com/spf13/cobra"
13-
"google.golang.org/grpc/status"
1413
)
1514

1615
func checkSchemaCmd(cdk *CDK) *cobra.Command {
1716
var comp, file, namespaceID string
18-
var req stencilv1beta1.CheckCompatibilityRequest
1917

2018
cmd := &cobra.Command{
2119
Use: "check <id>",
@@ -36,23 +34,23 @@ func checkSchemaCmd(cdk *CDK) *cobra.Command {
3634
return err
3735
}
3836

39-
client, cancel, err := createClient(cmd, cdk)
37+
client, err := createClient(cmd, cdk)
4038
if err != nil {
4139
return err
4240
}
43-
defer cancel()
4441

4542
schemaID := args[0]
4643

47-
req.Data = fileData
48-
req.NamespaceId = namespaceID
49-
req.SchemaId = schemaID
50-
req.Compatibility = stencilv1beta1.Schema_Compatibility(stencilv1beta1.Schema_Compatibility_value[comp])
44+
req := &stencilv1beta1.CheckCompatibilityRequest{
45+
Data: fileData,
46+
NamespaceId: namespaceID,
47+
SchemaId: schemaID,
48+
Compatibility: stencilv1beta1.Schema_Compatibility(stencilv1beta1.Schema_Compatibility_value[comp]),
49+
}
5150

52-
_, err = client.CheckCompatibility(context.Background(), &req)
51+
_, err = client.CheckCompatibility(context.Background(), connect.NewRequest(req))
5352
if err != nil {
54-
errStatus := status.Convert(err)
55-
return errors.New(errStatus.Message())
53+
return err
5654
}
5755

5856
spinner.Stop()

cmd/client.go

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,34 @@
11
package cmd
22

33
import (
4-
"context"
5-
"time"
4+
"net/http"
65

76
"github.com/raystack/salt/config"
8-
stencilv1beta1 "github.com/raystack/stencil/proto/raystack/stencil/v1beta1"
7+
stencilv1beta1connect "github.com/raystack/stencil/gen/raystack/stencil/v1beta1/stencilv1beta1connect"
98
"github.com/spf13/cobra"
10-
"google.golang.org/grpc"
11-
"google.golang.org/grpc/credentials/insecure"
129
)
1310

1411
type ClientConfig struct {
1512
Host string `yaml:"host" cmdx:"host"`
1613
}
1714

18-
func createConnection(ctx context.Context, host string) (*grpc.ClientConn, error) {
19-
opts := []grpc.DialOption{
20-
grpc.WithTransportCredentials(insecure.NewCredentials()),
21-
grpc.WithBlock(),
22-
}
23-
24-
return grpc.DialContext(ctx, host, opts...)
25-
}
26-
27-
func createClient(cmd *cobra.Command, cdk *CDK) (stencilv1beta1.StencilServiceClient, func(), error) {
15+
func createClient(cmd *cobra.Command, cdk *CDK) (stencilv1beta1connect.StencilServiceClient, error) {
2816
c, err := loadClientConfig(cmd, cdk.Config)
2917
if err != nil {
30-
return nil, nil, err
18+
return nil, err
3119
}
3220

3321
host := c.Host
3422

3523
if host == "" {
36-
return nil, nil, ErrClientConfigHostNotFound
37-
}
38-
39-
dialTimeoutCtx, dialCancel := context.WithTimeout(cmd.Context(), time.Second*2)
40-
conn, err := createConnection(dialTimeoutCtx, host)
41-
if err != nil {
42-
dialCancel()
43-
return nil, nil, err
44-
}
45-
46-
cancel := func() {
47-
dialCancel()
48-
conn.Close()
24+
return nil, ErrClientConfigHostNotFound
4925
}
5026

51-
client := stencilv1beta1.NewStencilServiceClient(conn)
52-
return client, cancel, nil
27+
client := stencilv1beta1connect.NewStencilServiceClient(
28+
http.DefaultClient,
29+
host,
30+
)
31+
return client, nil
5332
}
5433

5534
func loadClientConfig(cmd *cobra.Command, cmdxConfig *config.Loader) (*ClientConfig, error) {

cmd/create.go

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,60 @@ package cmd
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"os"
87

8+
"connectrpc.com/connect"
99
"github.com/MakeNowJust/heredoc"
1010
"github.com/raystack/salt/cli/printer"
11-
stencilv1beta1 "github.com/raystack/stencil/proto/raystack/stencil/v1beta1"
11+
stencilv1beta1 "github.com/raystack/stencil/gen/raystack/stencil/v1beta1"
1212
"github.com/spf13/cobra"
13-
"google.golang.org/grpc/codes"
14-
"google.golang.org/grpc/status"
1513
)
1614

1715
func createSchemaCmd(cdk *CDK) *cobra.Command {
1816
var format, comp, file, namespaceID string
19-
var req stencilv1beta1.CreateSchemaRequest
2017

2118
cmd := &cobra.Command{
2219
Use: "create",
2320
Short: "Create a schema",
2421
Args: cobra.ExactArgs(1),
2522
Example: heredoc.Doc(`
26-
$ stencil schema create booking -n raystack F booking.json
27-
$ stencil schema create booking -n raystack -f FORMAT_JSON c COMPATIBILITY_BACKWARD F ./booking.json
23+
$ stencil schema create booking -n raystack -F booking.json
24+
$ stencil schema create booking -n raystack -f FORMAT_JSON -c COMPATIBILITY_BACKWARD -F ./booking.json
2825
`),
2926
RunE: func(cmd *cobra.Command, args []string) error {
3027
fileData, err := os.ReadFile(file)
3128
if err != nil {
3229
return err
3330
}
34-
req.Data = fileData
3531

3632
spinner := printer.Spin("")
3733
defer spinner.Stop()
38-
client, cancel, err := createClient(cmd, cdk)
34+
client, err := createClient(cmd, cdk)
3935
if err != nil {
4036
return err
4137
}
42-
defer cancel()
4338

4439
schemaID := args[0]
45-
req.NamespaceId = namespaceID
46-
req.SchemaId = schemaID
47-
req.Format = stencilv1beta1.Schema_Format(stencilv1beta1.Schema_Format_value[format])
48-
req.Compatibility = stencilv1beta1.Schema_Compatibility(stencilv1beta1.Schema_Compatibility_value[comp])
40+
req := &stencilv1beta1.CreateSchemaRequest{
41+
NamespaceId: namespaceID,
42+
SchemaId: schemaID,
43+
Data: fileData,
44+
Format: stencilv1beta1.Schema_Format(stencilv1beta1.Schema_Format_value[format]),
45+
Compatibility: stencilv1beta1.Schema_Compatibility(stencilv1beta1.Schema_Compatibility_value[comp]),
46+
}
4947

50-
res, err := client.CreateSchema(context.Background(), &req)
48+
res, err := client.CreateSchema(context.Background(), connect.NewRequest(req))
5149
if err != nil {
52-
errStatus := status.Convert(err)
53-
if codes.AlreadyExists == errStatus.Code() {
50+
connectErr, ok := err.(*connect.Error)
51+
if ok && connectErr.Code() == connect.CodeAlreadyExists {
5452
fmt.Printf("\n%s Schema with id '%s' already exist.\n", printer.Icon("failure"), args[0])
5553
return nil
5654
}
57-
return errors.New(errStatus.Message())
55+
return err
5856
}
5957

60-
id := res.GetId()
58+
id := res.Msg.GetId()
6159

6260
spinner.Stop()
6361
fmt.Printf("\n%s Created schema with id %s.\n", printer.Green(printer.Icon("success")), printer.Cyan(id))

cmd/delete.go

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@ import (
44
"context"
55
"fmt"
66

7+
"connectrpc.com/connect"
78
"github.com/MakeNowJust/heredoc"
89
"github.com/raystack/salt/cli/printer"
9-
stencilv1beta1 "github.com/raystack/stencil/proto/raystack/stencil/v1beta1"
10+
stencilv1beta1 "github.com/raystack/stencil/gen/raystack/stencil/v1beta1"
1011
"github.com/spf13/cobra"
1112
)
1213

1314
func deleteSchemaCmd(cdk *CDK) *cobra.Command {
1415
var namespaceID string
15-
var req stencilv1beta1.DeleteSchemaRequest
16-
var reqVer stencilv1beta1.DeleteVersionRequest
1716
var version int32
1817

1918
cmd := &cobra.Command{
@@ -27,28 +26,27 @@ func deleteSchemaCmd(cdk *CDK) *cobra.Command {
2726
spinner := printer.Spin("")
2827
defer spinner.Stop()
2928

30-
client, cancel, err := createClient(cmd, cdk)
29+
client, err := createClient(cmd, cdk)
3130
if err != nil {
3231
return err
3332
}
34-
defer cancel()
3533

3634
schemaID := args[0]
3735

3836
if version == 0 {
39-
req.NamespaceId = namespaceID
40-
req.SchemaId = schemaID
41-
42-
_, err = client.DeleteSchema(context.Background(), &req)
37+
_, err = client.DeleteSchema(context.Background(), connect.NewRequest(&stencilv1beta1.DeleteSchemaRequest{
38+
NamespaceId: namespaceID,
39+
SchemaId: schemaID,
40+
}))
4341
if err != nil {
4442
return err
4543
}
4644
} else {
47-
reqVer.NamespaceId = namespaceID
48-
reqVer.SchemaId = schemaID
49-
reqVer.VersionId = version
50-
51-
_, err = client.DeleteVersion(context.Background(), &reqVer)
45+
_, err = client.DeleteVersion(context.Background(), connect.NewRequest(&stencilv1beta1.DeleteVersionRequest{
46+
NamespaceId: namespaceID,
47+
SchemaId: schemaID,
48+
VersionId: version,
49+
}))
5250
if err != nil {
5351
return err
5452
}

0 commit comments

Comments
 (0)